diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml index 93f292b471626885d06bcd5c13cd32333789e72f..c7aa5a7d6ed19fa2b7cce7760dc612c59bce87a7 100644 --- a/briar-android/res/values/strings.xml +++ b/briar-android/res/values/strings.xml @@ -53,4 +53,9 @@ <string name="create_identity_title">Create an Identity</string> <string name="choose_nickname">Choose your nickname:</string> <string name="create_button">Create</string> + <string name="no_contacts">You don\'t have any contacts. Add a contact now?</string> + <string name="add_contact_button">Add a contact</string> + <string name="cancel_button">Cancel</string> + <string name="no_groups">You aren\'t subscribed to any groups. Create a group now?</string> + <string name="create_group_button">Create a group</string> </resources> 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 0000000000000000000000000000000000000000..44809a3bf2343da4d1ebf65423e132b9daff8248 --- /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 0d7b970145d5fe1a3b5a083ff51befea3e203c3d..f13fce4f69fddc6279479d109aaa4a8b1ef22544 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<GroupMessageHeader> 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<GroupListItem> { 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 0000000000000000000000000000000000000000..59cd5c270c22a48d2869d35c2b3b3d907b06d425 --- /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 e887fc6561a2b142c649fb9b96014cc19ccd22e6..976bbb84b77b9d6c1ed14416cb1b4ca3782ae6c7 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<Group> 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 8fdc82aa3388d23eabafc01d10d1dbc03cbc24d6..950afba1c8e9755869893f363733d4492229c40d 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<Contact> contacts = db.getContacts(); + noContacts = contacts.isEmpty(); + for(Contact c : contacts) { try { // Load the headers from the database Collection<PrivateMessageHeader> 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<ConversationListItem> { 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 0000000000000000000000000000000000000000..d04aa9e84fcf956291dcfc5fb244ea94d8442b3c --- /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 c6480e0ac4231c0b13c81ebba45c518985178cd3..f3d714e07078217c7e058c3be2117c87115a7263 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<Contact> 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();