diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index a74ff9c72..2f6f1d7d1 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -15,6 +15,8 @@
Passwords do not match
Enter your password:
Wrong password, try again:
+ Briar could not start up
+ You may need to reinstall Briar.
This software has expired.\nPlease install a newer version.
Contacts
Forums
diff --git a/briar-android/src/org/briarproject/android/BriarService.java b/briar-android/src/org/briarproject/android/BriarService.java
index 2fc9b0172..c56714bdf 100644
--- a/briar-android/src/org/briarproject/android/BriarService.java
+++ b/briar-android/src/org/briarproject/android/BriarService.java
@@ -1,6 +1,7 @@
package org.briarproject.android;
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 java.util.logging.Level.INFO;
@@ -13,6 +14,7 @@ import org.briarproject.R;
import org.briarproject.api.android.AndroidExecutor;
import org.briarproject.api.db.DatabaseConfig;
import org.briarproject.api.lifecycle.LifecycleManager;
+
import roboguice.service.RoboService;
import android.app.PendingIntent;
import android.content.ComponentName;
@@ -30,11 +32,11 @@ public class BriarService extends RoboService {
private final Binder binder = new BriarBinder();
@Inject private DatabaseConfig databaseConfig;
- private boolean started = false;
// Fields that are accessed from background threads must be volatile
@Inject private volatile LifecycleManager lifecycleManager;
@Inject private volatile AndroidExecutor androidExecutor;
+ private volatile boolean started = false;
@Override
public void onCreate() {
@@ -51,21 +53,31 @@ public class BriarService extends RoboService {
b.setContentTitle(getText(R.string.notification_title));
b.setContentText(getText(R.string.notification_text));
b.setWhen(0); // Don't show the time
+ b.setOngoing(true);
// Touch the notification to show the home screen
Intent i = new Intent(this, HomeScreenActivity.class);
- i.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP);
- PendingIntent pi = PendingIntent.getActivity(this, 0, i, 0);
- b.setContentIntent(pi);
- b.setOngoing(true);
+ i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP |
+ FLAG_ACTIVITY_SINGLE_TOP);
+ b.setContentIntent(PendingIntent.getActivity(this, 0, i, 0));
startForeground(1, b.build());
// Start the services in a background thread
new Thread() {
@Override
public void run() {
- lifecycleManager.startServices();
+ if(lifecycleManager.startServices()) {
+ started = true;
+ } else {
+ if(LOG.isLoggable(INFO)) LOG.info("Startup failed");
+ Intent i = new Intent(BriarService.this,
+ HomeScreenActivity.class);
+ i.setFlags(FLAG_ACTIVITY_NEW_TASK |
+ FLAG_ACTIVITY_CLEAR_TOP);
+ i.putExtra("briar.STARTUP_FAILED", true);
+ startActivity(i);
+ stopSelf();
+ }
}
}.start();
- started = true;
}
@Override
@@ -84,11 +96,11 @@ public class BriarService extends RoboService {
super.onDestroy();
if(LOG.isLoggable(INFO)) LOG.info("Destroyed");
// Stop the services in a background thread
- if(started) new Thread() {
+ new Thread() {
@Override
public void run() {
androidExecutor.shutdown();
- lifecycleManager.stopServices();
+ if(started) lifecycleManager.stopServices();
}
}.start();
}
diff --git a/briar-android/src/org/briarproject/android/HomeScreenActivity.java b/briar-android/src/org/briarproject/android/HomeScreenActivity.java
index 7024486e5..488dce28b 100644
--- a/briar-android/src/org/briarproject/android/HomeScreenActivity.java
+++ b/briar-android/src/org/briarproject/android/HomeScreenActivity.java
@@ -1,5 +1,6 @@
package org.briarproject.android;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.text.InputType.TYPE_CLASS_TEXT;
import static android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD;
import static android.view.Gravity.CENTER;
@@ -41,10 +42,15 @@ import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.util.StringUtils;
import roboguice.activity.RoboActivity;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.IBinder;
+import android.support.v4.app.NotificationCompat;
import android.text.Editable;
import android.view.KeyEvent;
import android.view.View;
@@ -90,9 +96,17 @@ public class HomeScreenActivity extends RoboActivity {
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
+ if(LOG.isLoggable(INFO)) LOG.info("Created");
Intent i = getIntent();
- long handle = i.getLongExtra("org.briarproject.LOCAL_AUTHOR_HANDLE", -1);
- if(handle != -1) {
+ boolean failed = i.getBooleanExtra("briar.STARTUP_FAILED", false);
+ long handle = i.getLongExtra("briar.LOCAL_AUTHOR_HANDLE", -1);
+ if(failed) {
+ // LifecycleManager failed to start all necessary services
+ showStartupFailureNotification();
+ finish();
+ if(LOG.isLoggable(INFO)) LOG.info("Exiting");
+ System.exit(0);
+ } else if(handle != -1) {
// The activity was launched from the setup wizard
if(System.currentTimeMillis() < EXPIRY_DATE) {
showSpinner();
@@ -118,13 +132,30 @@ public class HomeScreenActivity extends RoboActivity {
}
}
+ private void showStartupFailureNotification() {
+ NotificationCompat.Builder b = new NotificationCompat.Builder(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));
+ // Touch the notification to relaunch the app
+ Intent i = new Intent(this, HomeScreenActivity.class);
+ i.setFlags(FLAG_ACTIVITY_NEW_TASK);
+ b.setContentIntent(PendingIntent.getActivity(this, 0, i, 0));
+ Notification n = b.build();
+ Object o = getSystemService(Context.NOTIFICATION_SERVICE);
+ NotificationManager nm = (NotificationManager) o;
+ nm.notify(0, n);
+ }
+
private void showSpinner() {
LinearLayout layout = new LinearLayout(this);
layout.setLayoutParams(MATCH_MATCH);
layout.setGravity(CENTER);
+
ProgressBar progress = new ProgressBar(this);
progress.setIndeterminate(true);
layout.addView(progress);
+
setContentView(layout);
}
diff --git a/briar-android/src/org/briarproject/android/SetupActivity.java b/briar-android/src/org/briarproject/android/SetupActivity.java
index 5aef39a82..bac901a07 100644
--- a/briar-android/src/org/briarproject/android/SetupActivity.java
+++ b/briar-android/src/org/briarproject/android/SetupActivity.java
@@ -247,7 +247,7 @@ public class SetupActivity extends RoboActivity implements OnClickListener {
public void run() {
Intent i = new Intent(SetupActivity.this,
HomeScreenActivity.class);
- i.putExtra("org.briarproject.LOCAL_AUTHOR_HANDLE", handle);
+ i.putExtra("briar.LOCAL_AUTHOR_HANDLE", handle);
i.setFlags(FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
finish();
diff --git a/briar-android/src/org/briarproject/android/contact/ContactListActivity.java b/briar-android/src/org/briarproject/android/contact/ContactListActivity.java
index b6852526f..98478a8f8 100644
--- a/briar-android/src/org/briarproject/android/contact/ContactListActivity.java
+++ b/briar-android/src/org/briarproject/android/contact/ContactListActivity.java
@@ -212,10 +212,10 @@ ConnectionListener {
GroupId inbox = item.getInboxGroupId();
AuthorId localAuthorId = item.getContact().getLocalAuthorId();
Intent i = new Intent(this, ConversationActivity.class);
- i.putExtra("org.briarproject.CONTACT_ID", contactId.getInt());
- i.putExtra("org.briarproject.CONTACT_NAME", contactName);
- i.putExtra("org.briarproject.GROUP_ID", inbox.getBytes());
- i.putExtra("org.briarproject.LOCAL_AUTHOR_ID", localAuthorId.getBytes());
+ i.putExtra("briar.CONTACT_ID", contactId.getInt());
+ i.putExtra("briar.CONTACT_NAME", contactName);
+ i.putExtra("briar.GROUP_ID", inbox.getBytes());
+ i.putExtra("briar.LOCAL_AUTHOR_ID", localAuthorId.getBytes());
startActivity(i);
}
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
index 08bf828b1..cb854dedf 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
@@ -68,16 +68,16 @@ implements EventListener, OnClickListener, OnItemClickListener {
super.onCreate(state);
Intent i = getIntent();
- int id = i.getIntExtra("org.briarproject.CONTACT_ID", -1);
+ int id = i.getIntExtra("briar.CONTACT_ID", -1);
if(id == -1) throw new IllegalStateException();
contactId = new ContactId(id);
- contactName = i.getStringExtra("org.briarproject.CONTACT_NAME");
+ contactName = i.getStringExtra("briar.CONTACT_NAME");
if(contactName == null) throw new IllegalStateException();
setTitle(contactName);
- byte[] b = i.getByteArrayExtra("org.briarproject.GROUP_ID");
+ byte[] b = i.getByteArrayExtra("briar.GROUP_ID");
if(b == null) throw new IllegalStateException();
groupId = new GroupId(b);
- b = i.getByteArrayExtra("org.briarproject.LOCAL_AUTHOR_ID");
+ b = i.getByteArrayExtra("briar.LOCAL_AUTHOR_ID");
if(b == null) throw new IllegalStateException();
localAuthorId = new AuthorId(b);
@@ -221,9 +221,9 @@ implements EventListener, OnClickListener, OnItemClickListener {
public void onClick(View view) {
Intent i = new Intent(this, WritePrivateMessageActivity.class);
- i.putExtra("org.briarproject.CONTACT_NAME", contactName);
- i.putExtra("org.briarproject.GROUP_ID", groupId.getBytes());
- i.putExtra("org.briarproject.LOCAL_AUTHOR_ID", localAuthorId.getBytes());
+ i.putExtra("briar.CONTACT_NAME", contactName);
+ i.putExtra("briar.GROUP_ID", groupId.getBytes());
+ i.putExtra("briar.LOCAL_AUTHOR_ID", localAuthorId.getBytes());
startActivity(i);
}
@@ -235,14 +235,14 @@ implements EventListener, OnClickListener, OnItemClickListener {
private void displayMessage(int position) {
MessageHeader header = adapter.getItem(position).getHeader();
Intent i = new Intent(this, ReadPrivateMessageActivity.class);
- i.putExtra("org.briarproject.CONTACT_ID", contactId.getInt());
- i.putExtra("org.briarproject.CONTACT_NAME", contactName);
- i.putExtra("org.briarproject.GROUP_ID", groupId.getBytes());
- i.putExtra("org.briarproject.LOCAL_AUTHOR_ID", localAuthorId.getBytes());
- i.putExtra("org.briarproject.AUTHOR_NAME", header.getAuthor().getName());
- i.putExtra("org.briarproject.MESSAGE_ID", header.getId().getBytes());
- i.putExtra("org.briarproject.CONTENT_TYPE", header.getContentType());
- i.putExtra("org.briarproject.TIMESTAMP", header.getTimestamp());
+ i.putExtra("briar.CONTACT_ID", contactId.getInt());
+ i.putExtra("briar.CONTACT_NAME", contactName);
+ i.putExtra("briar.GROUP_ID", groupId.getBytes());
+ i.putExtra("briar.LOCAL_AUTHOR_ID", localAuthorId.getBytes());
+ i.putExtra("briar.AUTHOR_NAME", header.getAuthor().getName());
+ i.putExtra("briar.MESSAGE_ID", header.getId().getBytes());
+ i.putExtra("briar.CONTENT_TYPE", header.getContentType());
+ i.putExtra("briar.TIMESTAMP", header.getTimestamp());
startActivityForResult(i, position);
}
}
diff --git a/briar-android/src/org/briarproject/android/contact/ReadPrivateMessageActivity.java b/briar-android/src/org/briarproject/android/contact/ReadPrivateMessageActivity.java
index ee27a2d85..932e6b49c 100644
--- a/briar-android/src/org/briarproject/android/contact/ReadPrivateMessageActivity.java
+++ b/briar-android/src/org/briarproject/android/contact/ReadPrivateMessageActivity.java
@@ -72,30 +72,30 @@ implements OnClickListener {
super.onCreate(state);
Intent i = getIntent();
- contactName = i.getStringExtra("org.briarproject.CONTACT_NAME");
+ contactName = i.getStringExtra("briar.CONTACT_NAME");
if(contactName == null) throw new IllegalStateException();
setTitle(contactName);
- byte[] b = i.getByteArrayExtra("org.briarproject.LOCAL_AUTHOR_ID");
+ byte[] b = i.getByteArrayExtra("briar.LOCAL_AUTHOR_ID");
if(b == null) throw new IllegalStateException();
localAuthorId = new AuthorId(b);
- String authorName = i.getStringExtra("org.briarproject.AUTHOR_NAME");
+ String authorName = i.getStringExtra("briar.AUTHOR_NAME");
if(authorName == null) throw new IllegalStateException();
- b = i.getByteArrayExtra("org.briarproject.MESSAGE_ID");
+ b = i.getByteArrayExtra("briar.MESSAGE_ID");
if(b == null) throw new IllegalStateException();
messageId = new MessageId(b);
- b = i.getByteArrayExtra("org.briarproject.GROUP_ID");
+ b = i.getByteArrayExtra("briar.GROUP_ID");
if(b == null) throw new IllegalStateException();
groupId = new GroupId(b);
- String contentType = i.getStringExtra("org.briarproject.CONTENT_TYPE");
+ String contentType = i.getStringExtra("briar.CONTENT_TYPE");
if(contentType == null) throw new IllegalStateException();
- timestamp = i.getLongExtra("org.briarproject.TIMESTAMP", -1);
+ timestamp = i.getLongExtra("briar.TIMESTAMP", -1);
if(timestamp == -1) throw new IllegalStateException();
if(state == null) {
read = false;
setReadInDatabase(true);
} else {
- read = state.getBoolean("org.briarproject.READ");
+ read = state.getBoolean("briar.READ");
}
LinearLayout layout = new LinearLayout(this);
@@ -257,7 +257,7 @@ implements OnClickListener {
@Override
public void onSaveInstanceState(Bundle state) {
super.onSaveInstanceState(state);
- state.putBoolean("org.briarproject.READ", read);
+ state.putBoolean("briar.READ", read);
}
public void onClick(View view) {
@@ -271,12 +271,12 @@ implements OnClickListener {
finish();
} else if(view == replyButton) {
Intent i = new Intent(this, WritePrivateMessageActivity.class);
- i.putExtra("org.briarproject.CONTACT_NAME", contactName);
- i.putExtra("org.briarproject.GROUP_ID", groupId.getBytes());
- i.putExtra("org.briarproject.LOCAL_AUTHOR_ID",
+ i.putExtra("briar.CONTACT_NAME", contactName);
+ i.putExtra("briar.GROUP_ID", groupId.getBytes());
+ i.putExtra("briar.LOCAL_AUTHOR_ID",
localAuthorId.getBytes());
- i.putExtra("org.briarproject.PARENT_ID", messageId.getBytes());
- i.putExtra("org.briarproject.TIMESTAMP", timestamp);
+ i.putExtra("briar.PARENT_ID", messageId.getBytes());
+ i.putExtra("briar.TIMESTAMP", timestamp);
startActivity(i);
setResult(RESULT_REPLY);
finish();
diff --git a/briar-android/src/org/briarproject/android/contact/WritePrivateMessageActivity.java b/briar-android/src/org/briarproject/android/contact/WritePrivateMessageActivity.java
index 847a472ff..1644cf527 100644
--- a/briar-android/src/org/briarproject/android/contact/WritePrivateMessageActivity.java
+++ b/briar-android/src/org/briarproject/android/contact/WritePrivateMessageActivity.java
@@ -78,17 +78,17 @@ implements OnClickListener {
super.onCreate(state);
Intent i = getIntent();
- contactName = i.getStringExtra("org.briarproject.CONTACT_NAME");
+ contactName = i.getStringExtra("briar.CONTACT_NAME");
if(contactName == null) throw new IllegalStateException();
- byte[] b = i.getByteArrayExtra("org.briarproject.GROUP_ID");
+ byte[] b = i.getByteArrayExtra("briar.GROUP_ID");
if(b == null) throw new IllegalStateException();
groupId = new GroupId(b);
- b = i.getByteArrayExtra("org.briarproject.LOCAL_AUTHOR_ID");
+ b = i.getByteArrayExtra("briar.LOCAL_AUTHOR_ID");
if(b == null) throw new IllegalStateException();
localAuthorId = new AuthorId(b);
- b = i.getByteArrayExtra("org.briarproject.PARENT_ID");
+ b = i.getByteArrayExtra("briar.PARENT_ID");
if(b != null) parentId = new MessageId(b);
- timestamp = i.getLongExtra("org.briarproject.TIMESTAMP", -1);
+ timestamp = i.getLongExtra("briar.TIMESTAMP", -1);
LinearLayout layout = new LinearLayout(this);
layout.setLayoutParams(MATCH_WRAP);
diff --git a/briar-android/src/org/briarproject/android/groups/ConfigureGroupActivity.java b/briar-android/src/org/briarproject/android/groups/ConfigureGroupActivity.java
index 56b9cffc0..91eb34ec2 100644
--- a/briar-android/src/org/briarproject/android/groups/ConfigureGroupActivity.java
+++ b/briar-android/src/org/briarproject/android/groups/ConfigureGroupActivity.java
@@ -69,17 +69,17 @@ SelectContactsDialog.Listener {
super.onCreate(state);
Intent i = getIntent();
- byte[] b = i.getByteArrayExtra("org.briarproject.GROUP_ID");
+ byte[] b = i.getByteArrayExtra("briar.GROUP_ID");
if(b == null) throw new IllegalStateException();
GroupId id = new GroupId(b);
- String name = i.getStringExtra("org.briarproject.GROUP_NAME");
+ String name = i.getStringExtra("briar.GROUP_NAME");
if(name == null) throw new IllegalStateException();
setTitle(name);
- b = i.getByteArrayExtra("org.briarproject.GROUP_SALT");
+ b = i.getByteArrayExtra("briar.GROUP_SALT");
if(b == null) throw new IllegalStateException();
group = new Group(id, name, b);
- subscribed = i.getBooleanExtra("org.briarproject.SUBSCRIBED", false);
- boolean all = i.getBooleanExtra("org.briarproject.VISIBLE_TO_ALL", false);
+ subscribed = i.getBooleanExtra("briar.SUBSCRIBED", false);
+ boolean all = i.getBooleanExtra("briar.VISIBLE_TO_ALL", false);
LinearLayout layout = new LinearLayout(this);
layout.setLayoutParams(MATCH_MATCH);
diff --git a/briar-android/src/org/briarproject/android/groups/GroupActivity.java b/briar-android/src/org/briarproject/android/groups/GroupActivity.java
index d37867ba2..11ff72b1e 100644
--- a/briar-android/src/org/briarproject/android/groups/GroupActivity.java
+++ b/briar-android/src/org/briarproject/android/groups/GroupActivity.java
@@ -67,10 +67,10 @@ OnClickListener, OnItemClickListener {
super.onCreate(state);
Intent i = getIntent();
- byte[] b = i.getByteArrayExtra("org.briarproject.GROUP_ID");
+ byte[] b = i.getByteArrayExtra("briar.GROUP_ID");
if(b == null) throw new IllegalStateException();
groupId = new GroupId(b);
- groupName = i.getStringExtra("org.briarproject.GROUP_NAME");
+ groupName = i.getStringExtra("briar.GROUP_NAME");
if(groupName == null) throw new IllegalStateException();
setTitle(groupName);
@@ -210,7 +210,7 @@ OnClickListener, OnItemClickListener {
public void onClick(View view) {
Intent i = new Intent(this, WriteGroupPostActivity.class);
- i.putExtra("org.briarproject.GROUP_ID", groupId.getBytes());
+ i.putExtra("briar.GROUP_ID", groupId.getBytes());
startActivity(i);
}
@@ -222,16 +222,16 @@ OnClickListener, OnItemClickListener {
private void displayMessage(int position) {
MessageHeader item = adapter.getItem(position);
Intent i = new Intent(this, ReadGroupPostActivity.class);
- i.putExtra("org.briarproject.GROUP_ID", groupId.getBytes());
- i.putExtra("org.briarproject.GROUP_NAME", groupName);
- i.putExtra("org.briarproject.MESSAGE_ID", item.getId().getBytes());
+ i.putExtra("briar.GROUP_ID", groupId.getBytes());
+ i.putExtra("briar.GROUP_NAME", groupName);
+ i.putExtra("briar.MESSAGE_ID", item.getId().getBytes());
Author author = item.getAuthor();
if(author != null) {
- i.putExtra("org.briarproject.AUTHOR_ID", author.getId().getBytes());
- i.putExtra("org.briarproject.AUTHOR_NAME", author.getName());
+ i.putExtra("briar.AUTHOR_ID", author.getId().getBytes());
+ i.putExtra("briar.AUTHOR_NAME", author.getName());
}
- i.putExtra("org.briarproject.CONTENT_TYPE", item.getContentType());
- i.putExtra("org.briarproject.TIMESTAMP", item.getTimestamp());
+ i.putExtra("briar.CONTENT_TYPE", item.getContentType());
+ i.putExtra("briar.TIMESTAMP", item.getTimestamp());
startActivityForResult(i, position);
}
}
diff --git a/briar-android/src/org/briarproject/android/groups/GroupListActivity.java b/briar-android/src/org/briarproject/android/groups/GroupListActivity.java
index d61c4148e..e1187e545 100644
--- a/briar-android/src/org/briarproject/android/groups/GroupListActivity.java
+++ b/briar-android/src/org/briarproject/android/groups/GroupListActivity.java
@@ -347,8 +347,8 @@ implements EventListener, OnClickListener, OnItemClickListener {
} else {
Intent i = new Intent(this, GroupActivity.class);
Group g = item.getGroup();
- i.putExtra("org.briarproject.GROUP_ID", g.getId().getBytes());
- i.putExtra("org.briarproject.GROUP_NAME", g.getName());
+ i.putExtra("briar.GROUP_ID", g.getId().getBytes());
+ i.putExtra("briar.GROUP_NAME", g.getName());
startActivity(i);
}
}
diff --git a/briar-android/src/org/briarproject/android/groups/ManageGroupsActivity.java b/briar-android/src/org/briarproject/android/groups/ManageGroupsActivity.java
index dc27eec0d..9eca0b78a 100644
--- a/briar-android/src/org/briarproject/android/groups/ManageGroupsActivity.java
+++ b/briar-android/src/org/briarproject/android/groups/ManageGroupsActivity.java
@@ -132,11 +132,11 @@ implements EventListener, OnItemClickListener {
GroupStatus s = item.getGroupStatus();
Group g = s.getGroup();
Intent i = new Intent(this, ConfigureGroupActivity.class);
- i.putExtra("org.briarproject.GROUP_ID", g.getId().getBytes());
- i.putExtra("org.briarproject.GROUP_NAME", g.getName());
- i.putExtra("org.briarproject.GROUP_SALT", g.getSalt());
- i.putExtra("org.briarproject.SUBSCRIBED", s.isSubscribed());
- i.putExtra("org.briarproject.VISIBLE_TO_ALL", s.isVisibleToAll());
+ i.putExtra("briar.GROUP_ID", g.getId().getBytes());
+ i.putExtra("briar.GROUP_NAME", g.getName());
+ i.putExtra("briar.GROUP_SALT", g.getSalt());
+ i.putExtra("briar.SUBSCRIBED", s.isSubscribed());
+ i.putExtra("briar.VISIBLE_TO_ALL", s.isVisibleToAll());
startActivity(i);
}
diff --git a/briar-android/src/org/briarproject/android/groups/ReadGroupPostActivity.java b/briar-android/src/org/briarproject/android/groups/ReadGroupPostActivity.java
index 6284aab72..83e97520d 100644
--- a/briar-android/src/org/briarproject/android/groups/ReadGroupPostActivity.java
+++ b/briar-android/src/org/briarproject/android/groups/ReadGroupPostActivity.java
@@ -69,26 +69,26 @@ implements OnClickListener {
super.onCreate(state);
Intent i = getIntent();
- byte[] b = i.getByteArrayExtra("org.briarproject.GROUP_ID");
+ byte[] b = i.getByteArrayExtra("briar.GROUP_ID");
if(b == null) throw new IllegalStateException();
groupId = new GroupId(b);
- String groupName = i.getStringExtra("org.briarproject.GROUP_NAME");
+ String groupName = i.getStringExtra("briar.GROUP_NAME");
if(groupName == null) throw new IllegalStateException();
setTitle(groupName);
- b = i.getByteArrayExtra("org.briarproject.MESSAGE_ID");
+ b = i.getByteArrayExtra("briar.MESSAGE_ID");
if(b == null) throw new IllegalStateException();
messageId = new MessageId(b);
- String contentType = i.getStringExtra("org.briarproject.CONTENT_TYPE");
+ String contentType = i.getStringExtra("briar.CONTENT_TYPE");
if(contentType == null) throw new IllegalStateException();
- timestamp = i.getLongExtra("org.briarproject.TIMESTAMP", -1);
+ timestamp = i.getLongExtra("briar.TIMESTAMP", -1);
if(timestamp == -1) throw new IllegalStateException();
- String authorName = i.getStringExtra("org.briarproject.AUTHOR_NAME");
+ String authorName = i.getStringExtra("briar.AUTHOR_NAME");
if(state == null) {
read = false;
setReadInDatabase(true);
} else {
- read = state.getBoolean("org.briarproject.READ");
+ read = state.getBoolean("briar.READ");
}
LinearLayout layout = new LinearLayout(this);
@@ -255,7 +255,7 @@ implements OnClickListener {
@Override
public void onSaveInstanceState(Bundle state) {
super.onSaveInstanceState(state);
- state.putBoolean("org.briarproject.READ", read);
+ state.putBoolean("briar.READ", read);
}
public void onClick(View view) {
@@ -269,9 +269,9 @@ implements OnClickListener {
finish();
} else if(view == replyButton) {
Intent i = new Intent(this, WriteGroupPostActivity.class);
- i.putExtra("org.briarproject.GROUP_ID", groupId.getBytes());
- i.putExtra("org.briarproject.PARENT_ID", messageId.getBytes());
- i.putExtra("org.briarproject.TIMESTAMP", timestamp);
+ i.putExtra("briar.GROUP_ID", groupId.getBytes());
+ i.putExtra("briar.PARENT_ID", messageId.getBytes());
+ i.putExtra("briar.TIMESTAMP", timestamp);
startActivity(i);
setResult(RESULT_REPLY);
finish();
diff --git a/briar-android/src/org/briarproject/android/groups/WriteGroupPostActivity.java b/briar-android/src/org/briarproject/android/groups/WriteGroupPostActivity.java
index b46e488a3..bedc77951 100644
--- a/briar-android/src/org/briarproject/android/groups/WriteGroupPostActivity.java
+++ b/briar-android/src/org/briarproject/android/groups/WriteGroupPostActivity.java
@@ -89,16 +89,16 @@ implements OnItemSelectedListener, OnClickListener {
super.onCreate(state);
Intent i = getIntent();
- byte[] b = i.getByteArrayExtra("org.briarproject.GROUP_ID");
+ byte[] b = i.getByteArrayExtra("briar.GROUP_ID");
if(b == null) throw new IllegalStateException();
groupId = new GroupId(b);
- b = i.getByteArrayExtra("org.briarproject.PARENT_ID");
+ b = i.getByteArrayExtra("briar.PARENT_ID");
if(b != null) parentId = new MessageId(b);
- timestamp = i.getLongExtra("org.briarproject.TIMESTAMP", -1);
+ timestamp = i.getLongExtra("briar.TIMESTAMP", -1);
if(state != null) {
- b = state.getByteArray("org.briarproject.LOCAL_AUTHOR_ID");
+ b = state.getByteArray("briar.LOCAL_AUTHOR_ID");
if(b != null) localAuthorId = new AuthorId(b);
}
@@ -214,7 +214,7 @@ implements OnItemSelectedListener, OnClickListener {
super.onSaveInstanceState(state);
if(localAuthorId != null) {
byte[] b = localAuthorId.getBytes();
- state.putByteArray("org.briarproject.LOCAL_AUTHOR_ID", b);
+ state.putByteArray("briar.LOCAL_AUTHOR_ID", b);
}
}
diff --git a/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java b/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java
index 6b3036d0d..b767b18b2 100644
--- a/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java
+++ b/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java
@@ -78,17 +78,17 @@ implements InvitationListener {
setView(new NetworkSetupView(this));
} else {
// Restore the activity's state
- byte[] b = state.getByteArray("org.briarproject.LOCAL_AUTHOR_ID");
+ byte[] b = state.getByteArray("briar.LOCAL_AUTHOR_ID");
if(b != null) localAuthorId = new AuthorId(b);
- taskHandle = state.getLong("org.briarproject.TASK_HANDLE", -1);
+ taskHandle = state.getLong("briar.TASK_HANDLE", -1);
task = referenceManager.getReference(taskHandle,
InvitationTask.class);
if(task == null) {
// No background task - we must be in an initial or final state
- localInvitationCode = state.getInt("org.briarproject.LOCAL_CODE");
- remoteInvitationCode = state.getInt("org.briarproject.REMOTE_CODE");
- connectionFailed = state.getBoolean("org.briarproject.FAILED");
- contactName = state.getString("org.briarproject.CONTACT_NAME");
+ localInvitationCode = state.getInt("briar.LOCAL_CODE");
+ remoteInvitationCode = state.getInt("briar.REMOTE_CODE");
+ connectionFailed = state.getBoolean("briar.FAILED");
+ contactName = state.getString("briar.CONTACT_NAME");
if(contactName != null) {
localCompared = remoteCompared = true;
localMatched = remoteMatched = true;
@@ -184,13 +184,13 @@ implements InvitationListener {
super.onSaveInstanceState(state);
if(localAuthorId != null) {
byte[] b = localAuthorId.getBytes();
- state.putByteArray("org.briarproject.LOCAL_AUTHOR_ID", b);
+ state.putByteArray("briar.LOCAL_AUTHOR_ID", b);
}
- state.putInt("org.briarproject.LOCAL_CODE", localInvitationCode);
- state.putInt("org.briarproject.REMOTE_CODE", remoteInvitationCode);
- state.putBoolean("org.briarproject.FAILED", connectionFailed);
- state.putString("org.briarproject.CONTACT_NAME", contactName);
- if(task != null) state.putLong("org.briarproject.TASK_HANDLE", taskHandle);
+ state.putInt("briar.LOCAL_CODE", localInvitationCode);
+ state.putInt("briar.REMOTE_CODE", remoteInvitationCode);
+ state.putBoolean("briar.FAILED", connectionFailed);
+ state.putString("briar.CONTACT_NAME", contactName);
+ if(task != null) state.putLong("briar.TASK_HANDLE", taskHandle);
}
@Override
diff --git a/briar-api/src/org/briarproject/api/db/DbSchemaException.java b/briar-api/src/org/briarproject/api/db/DbSchemaException.java
new file mode 100644
index 000000000..79dc98533
--- /dev/null
+++ b/briar-api/src/org/briarproject/api/db/DbSchemaException.java
@@ -0,0 +1,10 @@
+package org.briarproject.api.db;
+
+/**
+ * Thrown when the schema of the database differs from the schema expected by
+ * the code.
+ */
+public class DbSchemaException extends DbException {
+
+ private static final long serialVersionUID = -4444069279533651710L;
+}
diff --git a/briar-api/src/org/briarproject/api/lifecycle/LifecycleManager.java b/briar-api/src/org/briarproject/api/lifecycle/LifecycleManager.java
index f12e0f962..1df494ddb 100644
--- a/briar-api/src/org/briarproject/api/lifecycle/LifecycleManager.java
+++ b/briar-api/src/org/briarproject/api/lifecycle/LifecycleManager.java
@@ -13,8 +13,11 @@ public interface LifecycleManager {
*/
public void registerForShutdown(ExecutorService e);
- /** Starts any registered {@link Service}s. */
- public void startServices();
+ /**
+ * Starts any registered {@link Service}s and returns true if all services
+ * started successfully.
+ */
+ public boolean startServices();
/**
* Stops any registered {@link Service}s and shuts down any registered
diff --git a/briar-core/src/org/briarproject/db/JdbcDatabase.java b/briar-core/src/org/briarproject/db/JdbcDatabase.java
index 3f63d08c1..6f52733d7 100644
--- a/briar-core/src/org/briarproject/db/JdbcDatabase.java
+++ b/briar-core/src/org/briarproject/db/JdbcDatabase.java
@@ -34,6 +34,7 @@ import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.db.DbClosedException;
import org.briarproject.api.db.DbException;
+import org.briarproject.api.db.DbSchemaException;
import org.briarproject.api.db.MessageHeader;
import org.briarproject.api.messaging.Group;
import org.briarproject.api.messaging.GroupId;
@@ -56,6 +57,14 @@ import org.briarproject.api.transport.TemporarySecret;
*/
abstract class JdbcDatabase implements Database {
+ private static final int SCHEMA_VERSION = 1;
+
+ private static final String CREATE_SETTINGS =
+ "CREATE TABLE settings"
+ + " (key VARCHAR NOT NULL,"
+ + " value VARCHAR NOT NULL,"
+ + " PRIMARY KEY (key))";
+
// Locking: identity
// Dependents: contact, message, retention, subscription, transport, window
private static final String CREATE_LOCAL_AUTHORS =
@@ -356,7 +365,13 @@ abstract class JdbcDatabase implements Database {
// Open the database and create the tables if necessary
Connection txn = startTransaction();
try {
- if(!reopen) createTables(txn);
+ if(reopen) {
+ if(!checkSchemaVersion(txn))
+ throw new DbSchemaException();
+ } else {
+ createTables(txn);
+ setSchemaVersion(txn);
+ }
commitTransaction(txn);
} catch(DbException e) {
abortTransaction(txn);
@@ -364,10 +379,53 @@ abstract class JdbcDatabase implements Database {
}
}
+ private boolean checkSchemaVersion(Connection txn) throws DbException {
+ PreparedStatement ps = null;
+ ResultSet rs = null;
+ String value;
+ try {
+ String sql = "SELECT value FROM settings WHERE key = ?";
+ ps = txn.prepareStatement(sql);
+ ps.setString(1, "schemaVersion");
+ rs = ps.executeQuery();
+ if(!rs.next()) throw new DbStateException();
+ value = rs.getString(1);
+ if(rs.next()) throw new DbStateException();
+ rs.close();
+ ps.close();
+ } catch(SQLException e) {
+ tryToClose(rs);
+ tryToClose(ps);
+ throw new DbException(e);
+ }
+ try {
+ return Integer.valueOf(value) == SCHEMA_VERSION;
+ } catch(NumberFormatException e) {
+ throw new DbException(e);
+ }
+ }
+
+ private void tryToClose(ResultSet rs) {
+ if(rs != null) try {
+ rs.close();
+ } catch(SQLException e) {
+ if(LOG.isLoggable(WARNING))LOG.log(WARNING, e.toString(), e);
+ }
+ }
+
+ private void tryToClose(Statement s) {
+ if(s != null) try {
+ s.close();
+ } catch(SQLException e) {
+ if(LOG.isLoggable(WARNING))LOG.log(WARNING, e.toString(), e);
+ }
+ }
+
private void createTables(Connection txn) throws DbException {
Statement s = null;
try {
s = txn.createStatement();
+ s.executeUpdate(insertTypeNames(CREATE_SETTINGS));
s.executeUpdate(insertTypeNames(CREATE_LOCAL_AUTHORS));
s.executeUpdate(insertTypeNames(CREATE_CONTACTS));
s.executeUpdate(insertTypeNames(CREATE_GROUPS));
@@ -405,19 +463,19 @@ abstract class JdbcDatabase implements Database {
return s;
}
- private void tryToClose(Statement s) {
- if(s != null) try {
- s.close();
+ private void setSchemaVersion(Connection txn) throws DbException {
+ PreparedStatement ps = null;
+ try {
+ String sql = "INSERT INTO settings (key, value) VALUES (?, ?)";
+ ps = txn.prepareStatement(sql);
+ ps.setString(1, "schemaVersion");
+ ps.setString(2, String.valueOf(SCHEMA_VERSION));
+ int affected = ps.executeUpdate();
+ if(affected != 1) throw new DbStateException();
+ ps.close();
} catch(SQLException e) {
- if(LOG.isLoggable(WARNING))LOG.log(WARNING, e.toString(), e);
- }
- }
-
- private void tryToClose(ResultSet rs) {
- if(rs != null) try {
- rs.close();
- } catch(SQLException e) {
- if(LOG.isLoggable(WARNING))LOG.log(WARNING, e.toString(), e);
+ tryToClose(ps);
+ throw new DbException(e);
}
}
diff --git a/briar-core/src/org/briarproject/lifecycle/LifecycleManagerImpl.java b/briar-core/src/org/briarproject/lifecycle/LifecycleManagerImpl.java
index 128191776..c76b397ea 100644
--- a/briar-core/src/org/briarproject/lifecycle/LifecycleManagerImpl.java
+++ b/briar-core/src/org/briarproject/lifecycle/LifecycleManagerImpl.java
@@ -48,7 +48,7 @@ class LifecycleManagerImpl implements LifecycleManager {
executors.add(e);
}
- public void startServices() {
+ public boolean startServices() {
try {
if(LOG.isLoggable(INFO)) LOG.info("Starting");
boolean reopened = db.open();
@@ -64,12 +64,16 @@ class LifecycleManagerImpl implements LifecycleManager {
if(started) LOG.info("Service started: " + name);
else LOG.info("Service failed to start: " + name);
}
+ if(!started) return false;
}
startupLatch.countDown();
+ return true;
} catch(DbException e) {
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
+ return false;
} catch(IOException e) {
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
+ return false;
}
}
diff --git a/briar-tests/src/org/briarproject/TestLifecycleModule.java b/briar-tests/src/org/briarproject/TestLifecycleModule.java
index 94a8811c4..5f91d0ba6 100644
--- a/briar-tests/src/org/briarproject/TestLifecycleModule.java
+++ b/briar-tests/src/org/briarproject/TestLifecycleModule.java
@@ -17,7 +17,7 @@ public class TestLifecycleModule extends AbstractModule {
public void registerForShutdown(ExecutorService e) {}
- public void startServices() {}
+ public boolean startServices() { return true; }
public void stopServices() {}