"README.md" did not exist on "6cc864db2c52eabeba32de2b9521e5e9ba109cd4"
Newer
Older
package org.briarproject.android;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import org.briarproject.R;

Ernir Erlingsson
committed
import org.briarproject.android.api.AndroidExecutor;
import org.briarproject.api.db.DatabaseConfig;
import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.lifecycle.LifecycleManager.StartResult;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import javax.inject.Inject;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
import static android.support.v4.app.NotificationCompat.CATEGORY_SERVICE;
import static android.support.v4.app.NotificationCompat.PRIORITY_MIN;
import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
import static java.util.logging.Level.WARNING;
import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING;
import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
public class BriarService extends Service {
private static final int ONGOING_NOTIFICATION_ID = 1;
private static final int FAILURE_NOTIFICATION_ID = 2;
Logger.getLogger(BriarService.class.getName());
private final AtomicBoolean created = new AtomicBoolean(false);
private final Binder binder = new BriarBinder();

Ernir Erlingsson
committed
@Inject
protected DatabaseConfig databaseConfig;
// Fields that are accessed from background threads must be volatile

Ernir Erlingsson
committed
@Inject
protected volatile LifecycleManager lifecycleManager;
@Inject
protected volatile AndroidExecutor androidExecutor;
private volatile boolean started = false;
@Override
public void onCreate() {
super.onCreate();
BriarApplication application = (BriarApplication) getApplication();
application.getApplicationComponent().inject(this);
LOG.info("Created");
LOG.info("Already created");
stopSelf();
return;
}
if (databaseConfig.getEncryptionKey() == null) {
LOG.info("No database key");
stopSelf();
return;
}
// Show an ongoing notification that the service is running
NotificationCompat.Builder b = new NotificationCompat.Builder(this);
b.setSmallIcon(R.drawable.ongoing_notification_icon);
b.setContentTitle(getText(R.string.ongoing_notification_title));
b.setContentText(getText(R.string.ongoing_notification_text));
b.setWhen(0); // Don't show the time
Intent i = new Intent(this, NavDrawerActivity.class);
i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP |
FLAG_ACTIVITY_SINGLE_TOP);
b.setContentIntent(PendingIntent.getActivity(this, 0, i, 0));
if (Build.VERSION.SDK_INT >= 21) {
b.setCategory(CATEGORY_SERVICE);
b.setVisibility(VISIBILITY_SECRET);
}
b.setPriority(PRIORITY_MIN);
startForeground(ONGOING_NOTIFICATION_ID, b.build());
// Start the services in a background thread
new Thread() {
@Override
public void run() {
String nickname = databaseConfig.getLocalAuthorName();
StartResult result = lifecycleManager.startServices(nickname);
} else if (result == ALREADY_RUNNING) {
LOG.info("Already running");
stopSelf();
LOG.warning("Startup failed: " + result);
showStartupFailureNotification(result);
private void showStartupFailureNotification(final StartResult result) {
androidExecutor.runOnUiThread(new Runnable() {
@Override
public void run() {
NotificationCompat.Builder b =
new NotificationCompat.Builder(BriarService.this);
b.setSmallIcon(android.R.drawable.stat_notify_error);
b.setContentTitle(getText(
R.string.startup_failed_notification_title));
b.setContentText(getText(
R.string.startup_failed_notification_text));
Intent i = new Intent(BriarService.this,
StartupFailureActivity.class);
i.setFlags(FLAG_ACTIVITY_NEW_TASK);
i.putExtra("briar.START_RESULT", result);
i.putExtra("briar.FAILURE_NOTIFICATION_ID",
FAILURE_NOTIFICATION_ID);
b.setContentIntent(PendingIntent.getActivity(BriarService.this,
0, i, FLAG_UPDATE_CURRENT));
Object o = getSystemService(NOTIFICATION_SERVICE);
NotificationManager nm = (NotificationManager) o;
nm.notify(FAILURE_NOTIFICATION_ID, b.build());
// Bring the dashboard to the front to clear the back stack
i = new Intent(BriarService.this, NavDrawerActivity.class);
i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP);
i.putExtra("briar.STARTUP_FAILED", true);
startActivity(i);
}
});
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY; // Don't restart automatically if killed
@Override
@Override
public void onDestroy() {
super.onDestroy();
LOG.info("Destroyed");
stopForeground(true);
// Stop the services in a background thread
@Override
public void run() {
if (started) lifecycleManager.stopServices();
@Override
public void onLowMemory() {
super.onLowMemory();
LOG.warning("Memory is low");
// FIXME: Work out what to do about it
}

Ernir Erlingsson
committed
/**
* Waits for all services to start before returning.
*/
public void waitForStartup() throws InterruptedException {
lifecycleManager.waitForStartup();

Ernir Erlingsson
committed
/**
* Waits for all services to stop before returning.
*/
public void waitForShutdown() throws InterruptedException {
lifecycleManager.waitForShutdown();

Ernir Erlingsson
committed
/**
* Starts the shutdown process.
*/
public void shutdown() {
stopSelf(); // This will call onDestroy()
public class BriarBinder extends Binder {

Ernir Erlingsson
committed
/**
* Returns the bound service.
*/
public BriarService getService() {
return BriarService.this;
}
}
public static class BriarServiceConnection implements ServiceConnection {
private final CountDownLatch binderLatch = new CountDownLatch(1);
private volatile IBinder binder = null;
public void onServiceConnected(ComponentName name, IBinder binder) {
this.binder = binder;
binderLatch.countDown();
}

Ernir Erlingsson
committed
public void onServiceDisconnected(ComponentName name) {
}

Ernir Erlingsson
committed
/**
* Waits for the service to connect and returns its binder.
*/
public IBinder waitForBinder() throws InterruptedException {
binderLatch.await();
return binder;
}
}