threads now pooled
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>de.srsoftware</groupId>
|
||||
<artifactId>web4rail</artifactId>
|
||||
<version>1.2.63</version>
|
||||
<version>1.2.64</version>
|
||||
<name>Web4Rail</name>
|
||||
<packaging>jar</packaging>
|
||||
<description>Java Model Railway Control</description>
|
||||
|
||||
@@ -103,8 +103,9 @@ Emergency : Notfall
|
||||
enable {} : {} aktivieren
|
||||
export : exportieren
|
||||
Faster (10 {}) : 10 {} schneller
|
||||
Firing {} : starte {}
|
||||
Final speed after breaking, before halting : Endgeschwindigkeit nach Bremsvorgang, vor dem Anhalten
|
||||
FinishRoute : Route abschließen
|
||||
Firing {} : starte {}
|
||||
For each {} do: Für jede(n) {}:
|
||||
forward : vorwärts
|
||||
Found {} routes. : {} Routen gefunden.
|
||||
@@ -135,6 +136,7 @@ Locked by {} : Durch {} besetzt
|
||||
Locomotive manager : Lok-Verwaltung
|
||||
Locomotives\: : Lokomotiven:
|
||||
Locomotives and cars : Lokomotiven und Waggons
|
||||
Lower speed limit : Minimale Geschwindigkeit
|
||||
Manage cars : Waggons verwalten
|
||||
Manage locos : Lokomotiven verwalten
|
||||
Manage trains : Züge verwalten
|
||||
@@ -171,7 +173,7 @@ Origin\: {} to {} : Start: {} nach {}
|
||||
Plan saved as "{}". : Plan als „{}“ gespeichert.
|
||||
Port for state {} : Anschluss für Status {}
|
||||
PreserveRoute : Anschlußroute vorwählen
|
||||
Properties of plan : Plan-Eigenschaften
|
||||
Properties : Eigenschaften
|
||||
Properties of {} : Eigenschaften von {}
|
||||
Properties of {} @ ({},{}) : Eigenschaften von {} @ ({},{})
|
||||
PushPullTrain : Wendezug
|
||||
|
||||
@@ -15,6 +15,8 @@ import java.net.URLDecoder;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -40,6 +42,7 @@ import de.srsoftware.web4rail.tiles.Contact;
|
||||
public class Application extends BaseClass{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Application.class);
|
||||
private static final String START_TRAINS = "--start-trains";
|
||||
public static final ExecutorService threadPool = Executors.newCachedThreadPool();
|
||||
|
||||
/**
|
||||
* entry point for the application:<br/>
|
||||
@@ -63,7 +66,7 @@ public class Application extends BaseClass{
|
||||
server.createContext("/css" , client -> sendFile(client));
|
||||
server.createContext("/js" , client -> sendFile(client));
|
||||
server.createContext("/stream", client -> stream(client));
|
||||
server.setExecutor(java.util.concurrent.Executors.newCachedThreadPool());
|
||||
server.setExecutor(threadPool);
|
||||
server.start();
|
||||
try {
|
||||
Plan.load(Plan.DEFAULT_NAME);
|
||||
|
||||
@@ -206,7 +206,7 @@ public class ControlUnit extends Thread implements Constants{
|
||||
*/
|
||||
public ControlUnit restart() {
|
||||
end();
|
||||
start();
|
||||
Application.threadPool.execute(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -215,6 +215,16 @@ public class ControlUnit extends Thread implements Constants{
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
handshake(MODE_INFO);
|
||||
stopped = false;
|
||||
startInfoThread();
|
||||
handshake(MODE_COMMAND);
|
||||
} catch (IOException | TimeoutException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
while (!stopped) {
|
||||
try {
|
||||
if (queue.isEmpty()) {
|
||||
@@ -281,23 +291,10 @@ public class ControlUnit extends Thread implements Constants{
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void start() {
|
||||
try {
|
||||
handshake(MODE_INFO);
|
||||
stopped = false;
|
||||
startInfoThread();
|
||||
handshake(MODE_COMMAND);
|
||||
} catch (IOException | TimeoutException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
super.start();
|
||||
}
|
||||
|
||||
private void startInfoThread() {
|
||||
infoSocket = commandSocket; // handshake läuft immer über commandSocket und commandScanner
|
||||
infoScanner = commandScanner;
|
||||
new Thread(new Runnable() {
|
||||
Runnable infoThread = new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -315,12 +312,12 @@ public class ControlUnit extends Thread implements Constants{
|
||||
case FEEDBACK:
|
||||
int addr = Integer.parseInt(parts[5]);
|
||||
boolean active = !parts[6].equals("0");
|
||||
new Thread() {
|
||||
Application.threadPool.execute(new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
ControlUnit.this.plan.sensor(addr,active);
|
||||
}
|
||||
}.start();
|
||||
});
|
||||
case ACESSORY:
|
||||
break;
|
||||
default:
|
||||
@@ -342,7 +339,8 @@ public class ControlUnit extends Thread implements Constants{
|
||||
}
|
||||
|
||||
}
|
||||
}).start();
|
||||
};
|
||||
Application.threadPool.execute(infoThread);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -137,6 +137,7 @@ public class Plan extends BaseClass{
|
||||
private static final String SPEED_UNIT = "speed_unit";
|
||||
private static final String LENGTH_UNIT = "length_unit";
|
||||
private static final String CONFIRM = "confirm";
|
||||
private static final String FINAL_SPEED = "final_speed";
|
||||
|
||||
private ControlUnit controlUnit = new ControlUnit(this); // the control unit, to which the plan is connected
|
||||
private Contact learningContact;
|
||||
@@ -145,7 +146,7 @@ public class Plan extends BaseClass{
|
||||
* creates a new plan, starts to send heart beats
|
||||
*/
|
||||
public Plan() {
|
||||
new Heartbeat().start();
|
||||
Application.threadPool.execute(new Heartbeat());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -269,7 +270,7 @@ public class Plan extends BaseClass{
|
||||
return win;
|
||||
}
|
||||
|
||||
new Thread() {
|
||||
Application.threadPool.execute(new Thread() {
|
||||
public void run() {
|
||||
Vector<Route> newRoutes = new Vector<Route>();
|
||||
for (Block block : BaseClass.listElements(Block.class)) {
|
||||
@@ -286,7 +287,7 @@ public class Plan extends BaseClass{
|
||||
|
||||
stream(t("Found {} routes.",newRoutes.size()));
|
||||
}
|
||||
}.start();
|
||||
});
|
||||
|
||||
return t("Analyzing plan...");
|
||||
}
|
||||
@@ -308,6 +309,11 @@ public class Plan extends BaseClass{
|
||||
public ControlUnit controlUnit() {
|
||||
return controlUnit;
|
||||
}
|
||||
|
||||
public void drop(Tile tile) {
|
||||
tile.unregister();
|
||||
stream("remove "+tile.id());
|
||||
}
|
||||
|
||||
/**
|
||||
* completes a given route during a call to {@link #analyze()}.
|
||||
@@ -427,6 +433,21 @@ public class Plan extends BaseClass{
|
||||
LOG.debug("learning contact {}",learningContact);
|
||||
}
|
||||
|
||||
public JSONObject json() {
|
||||
JSONArray jTiles = new JSONArray();
|
||||
BaseClass.listElements(Tile.class)
|
||||
.stream()
|
||||
.filter(tile -> !(tile instanceof Shadow || tile instanceof BlockContact))
|
||||
.map(tile -> tile.json())
|
||||
.forEach(jTiles::put);
|
||||
|
||||
return new JSONObject()
|
||||
.put(TILE, jTiles)
|
||||
.put(SPEED_UNIT, speedUnit)
|
||||
.put(LENGTH_UNIT, lengthUnit)
|
||||
.put(FINAL_SPEED, Route.endSpeed);
|
||||
}
|
||||
|
||||
/**
|
||||
* loads a track layout from a file, along with its assigned cars, trains, routes and control unit settings
|
||||
* @param filename
|
||||
@@ -453,6 +474,7 @@ public class Plan extends BaseClass{
|
||||
if (json.has(TILE)) json.getJSONArray(TILE).forEach(object -> Tile.load(object, plan));
|
||||
if (json.has(LENGTH_UNIT)) lengthUnit = json.getString(LENGTH_UNIT);
|
||||
if (json.has(SPEED_UNIT)) speedUnit = json.getString(SPEED_UNIT);
|
||||
if (json.has(FINAL_SPEED)) Route.endSpeed = json.getInt(FINAL_SPEED);
|
||||
|
||||
try {
|
||||
Train.loadAll(filename+".trains",plan);
|
||||
@@ -470,7 +492,7 @@ public class Plan extends BaseClass{
|
||||
LOG.warn("Was not able to load control unit settings!",e);
|
||||
}
|
||||
try {
|
||||
plan.controlUnit.start();
|
||||
Application.threadPool.execute(plan.controlUnit);
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Was not able to establish connection to control unit!");
|
||||
}
|
||||
@@ -566,11 +588,6 @@ public class Plan extends BaseClass{
|
||||
return t(moved ? "Tile(s) moved.":"No tile moved.");
|
||||
}
|
||||
|
||||
public void drop(Tile tile) {
|
||||
tile.unregister();
|
||||
stream("remove "+tile.id());
|
||||
}
|
||||
|
||||
/**
|
||||
* adds a new tile to the plan on the client side
|
||||
* @param tile
|
||||
@@ -618,6 +635,7 @@ public class Plan extends BaseClass{
|
||||
new Input(ACTION,ACTION_UPDATE).hideIn(form);
|
||||
new Input(LENGTH_UNIT, lengthUnit).addTo(new Label(t("Length unit")+":"+NBSP)).addTo(form);
|
||||
new Input(SPEED_UNIT, speedUnit).addTo(new Label(t("Speed unit")+":"+NBSP)).addTo(form);
|
||||
new Input(FINAL_SPEED, Route.endSpeed).addTo(new Label(t("Lower speed limit")+":"+NBSP)).attr("title", t("Final speed after breaking, before halting")).addTo(form);
|
||||
new Button(t("Save"), form).addTo(form);
|
||||
form.addTo(win);
|
||||
|
||||
@@ -703,20 +721,6 @@ public class Plan extends BaseClass{
|
||||
|
||||
return t("Plan saved as \"{}\".",name);
|
||||
}
|
||||
|
||||
public JSONObject json() {
|
||||
JSONArray jTiles = new JSONArray();
|
||||
BaseClass.listElements(Tile.class)
|
||||
.stream()
|
||||
.filter(tile -> !(tile instanceof Shadow || tile instanceof BlockContact))
|
||||
.map(tile -> tile.json())
|
||||
.forEach(jTiles::put);
|
||||
|
||||
return new JSONObject()
|
||||
.put(TILE, jTiles)
|
||||
.put(SPEED_UNIT, speedUnit)
|
||||
.put(LENGTH_UNIT, lengthUnit);
|
||||
}
|
||||
|
||||
public void sensor(int addr, boolean active) {
|
||||
Contact contact = Contact.get(addr);
|
||||
@@ -857,6 +861,7 @@ public class Plan extends BaseClass{
|
||||
|
||||
if (params.containsKey(LENGTH_UNIT)) lengthUnit = params.get(LENGTH_UNIT);
|
||||
if (params.containsKey(SPEED_UNIT)) speedUnit = params.get(SPEED_UNIT);
|
||||
if (params.containsKey(FINAL_SPEED)) Route.endSpeed = Integer.parseInt(params.get(FINAL_SPEED));
|
||||
|
||||
return t("Plan updated.");
|
||||
|
||||
|
||||
@@ -69,22 +69,23 @@ public class Route extends BaseClass {
|
||||
static final String SIGNALS = "signals";
|
||||
static final String TURNOUTS = "turnouts";
|
||||
private State state = State.FREE;
|
||||
public static int endSpeed = 10;
|
||||
public static boolean freeBehindTrace = true;
|
||||
|
||||
private static final String ROUTE_START = "route_start";
|
||||
|
||||
private static final String ROUTE_SETUP = "route_setup";
|
||||
|
||||
private static HashMap<Id, String> names = new HashMap<Id, String>(); // maps id to name. needed to keep names during plan.analyze()
|
||||
|
||||
private class BrakeProcessor extends Thread {
|
||||
private int startSpeed;
|
||||
private static HashMap<Id, String> names = new HashMap<Id, String>(); // maps id to name. needed to keep names during plan.analyze()
|
||||
|
||||
private class BrakeProcessor extends Thread {
|
||||
private long timestamp;
|
||||
private Integer timeStep;
|
||||
private Route route;
|
||||
private Train train;
|
||||
private boolean aborted = false;
|
||||
private String brakeId;
|
||||
private static final int ENDSPEED = 10;
|
||||
|
||||
public BrakeProcessor(Route route, Train train) {
|
||||
this.train = train;
|
||||
@@ -109,7 +110,7 @@ public class Route extends BaseClass {
|
||||
//int remainingSpeed = train.speed;
|
||||
if (aborted) return;
|
||||
long runtime = timestamp2 - timestamp;
|
||||
int quotient = startSpeed - ENDSPEED;
|
||||
int quotient = startSpeed - endSpeed;
|
||||
if (quotient<1) quotient = 1;
|
||||
int newTimeStep = 5*(int) runtime/quotient;
|
||||
|
||||
@@ -128,7 +129,7 @@ public class Route extends BaseClass {
|
||||
public void run() {
|
||||
timestamp = new Date().getTime();
|
||||
if (train.speed == 0) aborted = true;
|
||||
while (train.speed > ENDSPEED) {
|
||||
while (train.speed > endSpeed) {
|
||||
if (aborted || train.nextRoutePrepared()) break;
|
||||
train.setSpeed(train.speed - 5);
|
||||
try {
|
||||
@@ -423,7 +424,9 @@ public class Route extends BaseClass {
|
||||
public void finish() {
|
||||
context.clear(); // prevent delayed actions from firing after route has finished
|
||||
setSignals(Signal.STOP);
|
||||
for (Tile tile : path) tile.unset(this);
|
||||
for (Tile tile : path) try {
|
||||
tile.unset(this);
|
||||
} catch (IllegalArgumentException e) {}
|
||||
Tile lastTile = path.lastElement();
|
||||
if (lastTile instanceof Contact) {
|
||||
lastTile.setTrain(null);
|
||||
@@ -439,7 +442,7 @@ public class Route extends BaseClass {
|
||||
train.setWaitTime(endBlock.getWaitTime(train,train.direction()));
|
||||
}
|
||||
if (train.route == this) train.route = null;
|
||||
if (!train.onTrace(startBlock)) startBlock.setTrain(null);
|
||||
if (!train.onTrace(startBlock) && startBlock.train() == train) startBlock.setTrain(null);
|
||||
}
|
||||
train = null;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import java.util.List;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import de.srsoftware.tools.Tag;
|
||||
import de.srsoftware.web4rail.Application;
|
||||
import de.srsoftware.web4rail.BaseClass;
|
||||
import de.srsoftware.web4rail.Window;
|
||||
import de.srsoftware.web4rail.tags.Fieldset;
|
||||
@@ -27,7 +28,7 @@ public class DelayedAction extends ActionList {
|
||||
|
||||
@Override
|
||||
public boolean fire(Context context) {
|
||||
new Thread() {
|
||||
Application.threadPool.execute(new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(delay);
|
||||
@@ -37,7 +38,7 @@ public class DelayedAction extends ActionList {
|
||||
}
|
||||
DelayedAction.super.fire(context);
|
||||
};
|
||||
}.start();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.util.List;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import de.srsoftware.web4rail.Application;
|
||||
import de.srsoftware.web4rail.BaseClass;
|
||||
import de.srsoftware.web4rail.Window;
|
||||
import de.srsoftware.web4rail.moving.Train;
|
||||
@@ -38,14 +39,14 @@ public class SetContextTrain extends Action {
|
||||
Id trainId = Id.from(json,REALM_TRAIN);
|
||||
if (isSet(trainId)) {
|
||||
train = Train.get(trainId);
|
||||
if (isNull(train)) new Thread() { // load asynchronously, as referred tile may not be available,yet
|
||||
if (isNull(train)) Application.threadPool.execute(new Thread() { // load asynchronously, as referred tile may not be available,yet
|
||||
public void run() {
|
||||
try {
|
||||
sleep(1000);
|
||||
train = Train.get(trainId);
|
||||
} catch (InterruptedException e) {}
|
||||
};
|
||||
}.start();
|
||||
});
|
||||
}
|
||||
}
|
||||
return this;
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.util.List;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import de.srsoftware.web4rail.Application;
|
||||
import de.srsoftware.web4rail.BaseClass;
|
||||
import de.srsoftware.web4rail.Window;
|
||||
import de.srsoftware.web4rail.tags.Fieldset;
|
||||
@@ -39,14 +40,14 @@ public class SetDisplayText extends TextAction{
|
||||
@Override
|
||||
public Action load(JSONObject json) {
|
||||
if (json.has(DISPLAY)) {
|
||||
new Thread() { // load asynchronously, as referred tile may not be available,yet
|
||||
Application.threadPool.execute(new Thread() { // load asynchronously, as referred tile may not be available,yet
|
||||
public void run() {
|
||||
try {
|
||||
sleep(1000);
|
||||
display = (TextDisplay) plan.get(Id.from(json,DISPLAY), false);
|
||||
} catch (InterruptedException e) {}
|
||||
};
|
||||
}.start();
|
||||
});
|
||||
}
|
||||
return super.load(json);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.util.List;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import de.srsoftware.web4rail.Application;
|
||||
import de.srsoftware.web4rail.BaseClass;
|
||||
import de.srsoftware.web4rail.Window;
|
||||
import de.srsoftware.web4rail.tags.Fieldset;
|
||||
@@ -43,14 +44,14 @@ public class SetRelay extends Action {
|
||||
if (json.has(RELAY)) {
|
||||
String relayId = json.getString(RELAY);
|
||||
relay = BaseClass.get(new Id(relayId));
|
||||
if (isNull(relay)) new Thread() { // if relay not loaded, yet: wait one sec and try again
|
||||
if (isNull(relay)) Application.threadPool.execute(new Thread() { // if relay not loaded, yet: wait one sec and try again
|
||||
public void run() {
|
||||
try {
|
||||
sleep(1000);
|
||||
} catch (InterruptedException e) {}
|
||||
relay = BaseClass.get(new Id(relayId));
|
||||
};
|
||||
}.start();
|
||||
});
|
||||
}
|
||||
if (json.has(Relay.STATE)) state = json.getBoolean(Relay.STATE);
|
||||
return this;
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import de.srsoftware.tools.Tag;
|
||||
import de.srsoftware.web4rail.Application;
|
||||
import de.srsoftware.web4rail.BaseClass;
|
||||
import de.srsoftware.web4rail.PathFinder;
|
||||
import de.srsoftware.web4rail.Plan;
|
||||
@@ -216,7 +217,7 @@ public class Train extends BaseClass implements Comparable<Train> {
|
||||
public String automatic() {
|
||||
if (isNull(autopilot)) {
|
||||
autopilot = new Autopilot();
|
||||
autopilot.start();
|
||||
Application.threadPool.execute(autopilot);
|
||||
if (isSet(currentBlock)) plan.place(currentBlock);
|
||||
}
|
||||
return t("{} now in auto-mode",this);
|
||||
@@ -740,6 +741,9 @@ public class Train extends BaseClass implements Comparable<Train> {
|
||||
tile.setTrain(this);
|
||||
} else {
|
||||
tile.setTrain(null);
|
||||
if (Route.freeBehindTrace) try {
|
||||
tile.unset(route);
|
||||
} catch (IllegalArgumentException e) {}
|
||||
trace.remove(i);
|
||||
i--; // do not move to next index: remove shifted the next index towards us
|
||||
}
|
||||
@@ -803,7 +807,7 @@ public class Train extends BaseClass implements Comparable<Train> {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
plan.stream(t("Simulating movement of {}...",this));
|
||||
new Thread() {
|
||||
Application.threadPool.execute(new Thread() {
|
||||
public void run() {
|
||||
for (Tile tile : route.path()) {
|
||||
if (isNull(route)) break;
|
||||
@@ -820,7 +824,7 @@ public class Train extends BaseClass implements Comparable<Train> {
|
||||
}
|
||||
}
|
||||
};
|
||||
}.start();
|
||||
});
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import java.util.Map;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import de.srsoftware.tools.Tag;
|
||||
import de.srsoftware.web4rail.Application;
|
||||
import de.srsoftware.web4rail.BaseClass;
|
||||
import de.srsoftware.web4rail.Connector;
|
||||
import de.srsoftware.web4rail.Route;
|
||||
@@ -51,7 +52,7 @@ public abstract class Bridge extends Tile {
|
||||
@Override
|
||||
public Tile load(JSONObject json) {
|
||||
if (json.has(COUNTERPART)) {
|
||||
new Thread() {
|
||||
Application.threadPool.execute(new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
@@ -61,7 +62,7 @@ public abstract class Bridge extends Tile {
|
||||
}
|
||||
counterpart = (Bridge) plan.get(Id.from(json, COUNTERPART), false);
|
||||
}
|
||||
}.start();
|
||||
});
|
||||
}
|
||||
return super.load(json);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import de.srsoftware.tools.Tag;
|
||||
import de.srsoftware.web4rail.Application;
|
||||
import de.srsoftware.web4rail.BaseClass;
|
||||
import de.srsoftware.web4rail.Route;
|
||||
import de.srsoftware.web4rail.Window;
|
||||
@@ -43,7 +44,7 @@ public class Contact extends Tile{
|
||||
boolean aborted = false;
|
||||
|
||||
public OffTimer() {
|
||||
start();
|
||||
Application.threadPool.execute(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -232,14 +233,14 @@ public class Contact extends Tile{
|
||||
|
||||
public boolean trigger(int duration) {
|
||||
activate(true);
|
||||
new Thread() {
|
||||
Application.threadPool.execute(new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
sleep(duration);
|
||||
activate(false);
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
}.start();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user