diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index 93f292b47..c7aa5a7d6 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -53,4 +53,9 @@
Create an Identity
Choose your nickname:
Create
+ You don\'t have any contacts. Add a contact now?
+ Add a contact
+ Cancel
+ You aren\'t subscribed to any groups. Create a group now?
+ Create a group
diff --git a/briar-android/src/net/sf/briar/android/BriarFragmentActivity.java b/briar-android/src/net/sf/briar/android/BriarFragmentActivity.java
new file mode 100644
index 000000000..44809a3bf
--- /dev/null
+++ b/briar-android/src/net/sf/briar/android/BriarFragmentActivity.java
@@ -0,0 +1,36 @@
+package net.sf.briar.android;
+
+import roboguice.activity.RoboFragmentActivity;
+import android.os.Bundle;
+
+/**
+ * An abstract superclass for activities that overrides the default behaviour
+ * to prevent sensitive state from being saved unless the subclass explicitly
+ * saves it.
+ */
+public class BriarFragmentActivity extends RoboFragmentActivity {
+
+ @Override
+ public void onCreate(Bundle state) {
+ // Don't pass state through to the superclass
+ super.onCreate(null);
+ }
+
+ @Override
+ public void onRestoreInstanceState(Bundle state) {
+ // Don't pass state through to the superclass
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle state) {
+ // Don't allow the superclass to save state
+ }
+
+ protected void finishOnUiThread() {
+ runOnUiThread(new Runnable() {
+ public void run() {
+ finish();
+ }
+ });
+ }
+}
diff --git a/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java b/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java
index 0d7b97014..f13fce4f6 100644
--- a/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java
+++ b/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java
@@ -18,7 +18,7 @@ import java.util.concurrent.Executor;
import java.util.logging.Logger;
import net.sf.briar.R;
-import net.sf.briar.android.BriarActivity;
+import net.sf.briar.android.BriarFragmentActivity;
import net.sf.briar.android.BriarService;
import net.sf.briar.android.BriarService.BriarServiceConnection;
import net.sf.briar.android.widgets.HorizontalBorder;
@@ -45,8 +45,8 @@ import android.widget.ListView;
import com.google.inject.Inject;
-public class GroupListActivity extends BriarActivity
-implements OnClickListener, DatabaseListener {
+public class GroupListActivity extends BriarFragmentActivity
+implements OnClickListener, DatabaseListener, NoGroupsDialog.Listener {
private static final Logger LOG =
Logger.getLogger(GroupListActivity.class.getName());
@@ -62,6 +62,7 @@ implements OnClickListener, DatabaseListener {
@Inject private volatile DatabaseComponent db;
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
private volatile boolean restricted = false;
+ private volatile boolean noGroups = true;
@Override
public void onCreate(Bundle state) {
@@ -135,6 +136,7 @@ implements OnClickListener, DatabaseListener {
for(Group g : db.getSubscriptions()) {
// Filter out restricted/unrestricted groups
if(g.isRestricted() != restricted) continue;
+ noGroups = false;
try {
// Load the headers from the database
Collection headers =
@@ -217,9 +219,15 @@ implements OnClickListener, DatabaseListener {
if(view == newGroupButton) {
// FIXME: Hook this button up to an activity
} else if(view == composeButton) {
- Intent i = new Intent(this, WriteGroupMessageActivity.class);
- i.putExtra("net.sf.briar.RESTRICTED", restricted);
- startActivity(i);
+ if(noGroups) {
+ NoGroupsDialog dialog = new NoGroupsDialog();
+ dialog.setListener(this);
+ dialog.show(getSupportFragmentManager(), "NoGroupsDialog");
+ } else {
+ Intent i = new Intent(this, WriteGroupMessageActivity.class);
+ i.putExtra("net.sf.briar.RESTRICTED", restricted);
+ startActivity(i);
+ }
}
}
@@ -282,6 +290,14 @@ implements OnClickListener, DatabaseListener {
});
}
+ public void createGroupButtonClicked() {
+ // FIXME: Hook this button up to an activity
+ }
+
+ public void cancelButtonClicked() {
+ // That's nice dear
+ }
+
private static class GroupComparator implements Comparator {
private static final GroupComparator INSTANCE = new GroupComparator();
diff --git a/briar-android/src/net/sf/briar/android/groups/NoGroupsDialog.java b/briar-android/src/net/sf/briar/android/groups/NoGroupsDialog.java
new file mode 100644
index 000000000..59cd5c270
--- /dev/null
+++ b/briar-android/src/net/sf/briar/android/groups/NoGroupsDialog.java
@@ -0,0 +1,43 @@
+package net.sf.briar.android.groups;
+
+import net.sf.briar.R;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+
+public class NoGroupsDialog extends DialogFragment {
+
+ private Listener listener = null;
+
+ void setListener(Listener listener) {
+ this.listener = listener;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle state) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setMessage(R.string.no_groups);
+ builder.setPositiveButton(R.string.create_group_button,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ listener.createGroupButtonClicked();
+ }
+ });
+ builder.setNegativeButton(R.string.cancel_button,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ listener.cancelButtonClicked();
+ }
+ });
+ return builder.create();
+ }
+
+ interface Listener {
+
+ void createGroupButtonClicked();
+
+ void cancelButtonClicked();
+ }
+}
diff --git a/briar-android/src/net/sf/briar/android/groups/WriteGroupMessageActivity.java b/briar-android/src/net/sf/briar/android/groups/WriteGroupMessageActivity.java
index e887fc656..976bbb84b 100644
--- a/briar-android/src/net/sf/briar/android/groups/WriteGroupMessageActivity.java
+++ b/briar-android/src/net/sf/briar/android/groups/WriteGroupMessageActivity.java
@@ -213,6 +213,7 @@ implements OnItemSelectedListener, OnClickListener {
private void displayGroups(final Collection groups) {
runOnUiThread(new Runnable() {
public void run() {
+ if(groups.isEmpty()) finish();
int index = -1;
for(Group g : groups) {
if(g.getId().equals(groupId)) {
diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java b/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java
index 8fdc82aa3..950afba1c 100644
--- a/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java
+++ b/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java
@@ -15,9 +15,10 @@ import java.util.concurrent.Executor;
import java.util.logging.Logger;
import net.sf.briar.R;
-import net.sf.briar.android.BriarActivity;
+import net.sf.briar.android.BriarFragmentActivity;
import net.sf.briar.android.BriarService;
import net.sf.briar.android.BriarService.BriarServiceConnection;
+import net.sf.briar.android.invitation.AddContactActivity;
import net.sf.briar.android.widgets.HorizontalBorder;
import net.sf.briar.api.Contact;
import net.sf.briar.api.ContactId;
@@ -41,8 +42,8 @@ import android.widget.ListView;
import com.google.inject.Inject;
-public class ConversationListActivity extends BriarActivity
-implements OnClickListener, DatabaseListener {
+public class ConversationListActivity extends BriarFragmentActivity
+implements OnClickListener, DatabaseListener, NoContactsDialog.Listener {
private static final Logger LOG =
Logger.getLogger(ConversationListActivity.class.getName());
@@ -56,6 +57,7 @@ implements OnClickListener, DatabaseListener {
// Fields that are accessed from background threads must be volatile
@Inject private volatile DatabaseComponent db;
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
+ private volatile boolean noContacts = true;
@Override
public void onCreate(Bundle state) {
@@ -103,7 +105,9 @@ implements OnClickListener, DatabaseListener {
serviceConnection.waitForStartup();
// Load the contact list from the database
long now = System.currentTimeMillis();
- for(Contact c : db.getContacts()) {
+ Collection contacts = db.getContacts();
+ noContacts = contacts.isEmpty();
+ for(Contact c : contacts) {
try {
// Load the headers from the database
Collection headers =
@@ -183,7 +187,13 @@ implements OnClickListener, DatabaseListener {
}
public void onClick(View view) {
- startActivity(new Intent(this, WritePrivateMessageActivity.class));
+ if(noContacts) {
+ NoContactsDialog dialog = new NoContactsDialog();
+ dialog.setListener(this);
+ dialog.show(getSupportFragmentManager(), "NoContactsDialog");
+ } else {
+ startActivity(new Intent(this, WritePrivateMessageActivity.class));
+ }
}
public void eventOccurred(DatabaseEvent e) {
@@ -240,6 +250,14 @@ implements OnClickListener, DatabaseListener {
});
}
+ public void addContactButtonClicked() {
+ startActivity(new Intent(this, AddContactActivity.class));
+ }
+
+ public void cancelButtonClicked() {
+ // That's nice dear
+ }
+
private static class ConversationComparator
implements Comparator {
diff --git a/briar-android/src/net/sf/briar/android/messages/NoContactsDialog.java b/briar-android/src/net/sf/briar/android/messages/NoContactsDialog.java
new file mode 100644
index 000000000..d04aa9e84
--- /dev/null
+++ b/briar-android/src/net/sf/briar/android/messages/NoContactsDialog.java
@@ -0,0 +1,43 @@
+package net.sf.briar.android.messages;
+
+import net.sf.briar.R;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+
+public class NoContactsDialog extends DialogFragment {
+
+ private Listener listener = null;
+
+ void setListener(Listener listener) {
+ this.listener = listener;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle state) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setMessage(R.string.no_contacts);
+ builder.setPositiveButton(R.string.add_contact_button,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ listener.addContactButtonClicked();
+ }
+ });
+ builder.setNegativeButton(R.string.cancel_button,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ listener.cancelButtonClicked();
+ }
+ });
+ return builder.create();
+ }
+
+ interface Listener {
+
+ void addContactButtonClicked();
+
+ void cancelButtonClicked();
+ }
+}
diff --git a/briar-android/src/net/sf/briar/android/messages/WritePrivateMessageActivity.java b/briar-android/src/net/sf/briar/android/messages/WritePrivateMessageActivity.java
index c6480e0ac..f3d714e07 100644
--- a/briar-android/src/net/sf/briar/android/messages/WritePrivateMessageActivity.java
+++ b/briar-android/src/net/sf/briar/android/messages/WritePrivateMessageActivity.java
@@ -164,6 +164,7 @@ implements OnItemSelectedListener, OnClickListener {
private void displayContacts(final Collection contacts) {
runOnUiThread(new Runnable() {
public void run() {
+ if(contacts.isEmpty()) finish();
int index = -1;
for(Contact c : contacts) {
if(c.getId().equals(contactId)) index = adapter.getCount();