diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml index 6cb529c8fd2df76fec26668f320e2abb115aeca1..d60559cb541c6ee2c3fe38364975686830e50363 100644 --- a/briar-android/res/values/strings.xml +++ b/briar-android/res/values/strings.xml @@ -6,6 +6,7 @@ <string name="welcome">Welcome to Briar! Add a contact to get started.</string> <string name="face_to_face">For security reasons you must be face to face with someone to add them as a contact.</string> <string name="add_contact_button">Add a contact</string> + <string name="quit_button">Quit</string> <string name="add_a_contact">Add a Contact</string> <string name="same_network">Briar can add contacts via Wi-Fi or Bluetooth. To use Wi-Fi you must both be connected to the same network.</string> <string name="wifi_not_available">Wi-Fi is not available on this device</string> diff --git a/briar-android/src/net/sf/briar/android/helloworld/HelloWorldActivity.java b/briar-android/src/net/sf/briar/android/helloworld/HelloWorldActivity.java index b3b4417d8cce36be57fbfe2df39d69e8a0c08c03..34fdc41323202ebcca8708c95577727e4a2d9a0f 100644 --- a/briar-android/src/net/sf/briar/android/helloworld/HelloWorldActivity.java +++ b/briar-android/src/net/sf/briar/android/helloworld/HelloWorldActivity.java @@ -1,36 +1,62 @@ package net.sf.briar.android.helloworld; +import static android.view.Gravity.CENTER; import static android.view.Gravity.CENTER_HORIZONTAL; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; +import static android.widget.LinearLayout.HORIZONTAL; import static android.widget.LinearLayout.VERTICAL; import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +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.BriarService; +import net.sf.briar.android.BriarService.BriarBinder; +import net.sf.briar.android.BriarService.BriarServiceConnection; import net.sf.briar.android.invitation.AddContactActivity; -import net.sf.briar.api.android.BundleEncrypter; +import net.sf.briar.api.Contact; +import net.sf.briar.api.db.DatabaseComponent; +import net.sf.briar.api.db.DatabaseExecutor; +import net.sf.briar.api.db.DbException; +import net.sf.briar.api.db.event.ContactAddedEvent; +import net.sf.briar.api.db.event.DatabaseEvent; +import net.sf.briar.api.db.event.DatabaseListener; import android.content.Intent; import android.os.Bundle; +import android.os.IBinder; import android.view.View; import android.view.View.OnClickListener; +import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.LinearLayout; +import android.widget.ListView; import android.widget.RelativeLayout.LayoutParams; import android.widget.TextView; import com.google.inject.Inject; public class HelloWorldActivity extends BriarActivity -implements OnClickListener { +implements OnClickListener, DatabaseListener { private static final Logger LOG = Logger.getLogger(HelloWorldActivity.class.getName()); - @Inject private BundleEncrypter bundleEncrypter; + private final BriarServiceConnection serviceConnection = + new BriarServiceConnection(); + + @Inject private DatabaseComponent db; + @Inject @DatabaseExecutor private Executor dbExecutor; + + Button addContact = null, quit = null; + private ArrayAdapter<String> adapter = null; @Override public void onCreate(Bundle state) { @@ -51,27 +77,140 @@ implements OnClickListener { faceToFace.setText(R.string.face_to_face); layout.addView(faceToFace); - Button addContact = new Button(this); + LinearLayout innerLayout = new LinearLayout(this); + innerLayout.setOrientation(HORIZONTAL); + innerLayout.setGravity(CENTER); + + addContact = new Button(this); LayoutParams lp = new LayoutParams(WRAP_CONTENT, WRAP_CONTENT); addContact.setLayoutParams(lp); addContact.setText(R.string.add_contact_button); addContact.setCompoundDrawablesWithIntrinsicBounds( R.drawable.social_add_person, 0, 0, 0); addContact.setOnClickListener(this); - layout.addView(addContact); + innerLayout.addView(addContact); + + quit = new Button(this); + quit.setLayoutParams(lp); + quit.setText(R.string.quit_button); + quit.setOnClickListener(this); + innerLayout.addView(quit); + layout.addView(innerLayout); + + adapter = new ArrayAdapter<String>(this, + android.R.layout.simple_expandable_list_item_1, + new ArrayList<String>()); + ListView listView = new ListView(this); + listView.setAdapter(adapter); + layout.addView(listView); setContentView(layout); + // Listen for database events + db.addListener(this); + + // Start the service and bind to it startService(new Intent(BriarService.class.getName())); - } + bindService(new Intent(BriarService.class.getName()), + serviceConnection, 0); - @Override - public void onDestroy() { - super.onDestroy(); - if(LOG.isLoggable(INFO)) LOG.info("Destroyed"); + // Add some fake contacts to the database in a background thread + dbExecutor.execute(new Runnable() { + public void run() { + try { + // Wait for the service to be bound and started + IBinder binder = serviceConnection.waitForBinder(); + ((BriarBinder) binder).getService().waitForStartup(); + if(LOG.isLoggable(INFO)) LOG.info("Service started"); + // Insert a couple of fake contacts + db.addContact("Alice"); + db.addContact("Bob"); + } catch(DbException e) { + if(LOG.isLoggable(WARNING)) + LOG.log(WARNING, e.toString(), e); + } catch(InterruptedException e) { + if(LOG.isLoggable(INFO)) + LOG.info("Interrupted while waiting for service"); + Thread.currentThread().interrupt(); + } + } + }); } public void onClick(View view) { - startActivity(new Intent(this, AddContactActivity.class)); + if(view == addContact) + startActivity(new Intent(this, AddContactActivity.class)); + else if(view == quit) + quit(); + } + + private void quit() { + new Thread() { + @Override + public void run() { + try { + // Wait for the service to be bound and started + IBinder binder = serviceConnection.waitForBinder(); + BriarService service = ((BriarBinder) binder).getService(); + service.waitForStartup(); + // Shut down the service and wait for it to shut down + if(LOG.isLoggable(INFO)) LOG.info("Shutting down service"); + service.shutdown(); + service.waitForShutdown(); + if(LOG.isLoggable(INFO)) LOG.info("Service shut down"); + // Unbind from the service and finish the activity + runOnUiThread(new Runnable() { + public void run() { + unbindService(serviceConnection); + finish(); + } + }); + } catch(InterruptedException e) { + if(LOG.isLoggable(INFO)) + LOG.info("Interrupted while waiting for service"); + } + } + }.start(); + } + + public void eventOccurred(DatabaseEvent e) { + if(e instanceof ContactAddedEvent) reloadContactList(); + } + + private void reloadContactList() { + dbExecutor.execute(new Runnable() { + public void run() { + try { + // Wait for the service to be bound and started + IBinder binder = serviceConnection.waitForBinder(); + ((BriarBinder) binder).getService().waitForStartup(); + // Load the contacts from the database + final Collection<Contact> contacts = db.getContacts(); + if(LOG.isLoggable(INFO)) + LOG.info("Loaded " + contacts.size() + " contacts"); + // Update the contact list on the UI thread + runOnUiThread(new Runnable() { + public void run() { + updateContactList(contacts); + } + }); + } catch(DbException e) { + if(LOG.isLoggable(WARNING)) + LOG.log(WARNING, e.toString(), e); + } catch(InterruptedException e) { + if(LOG.isLoggable(INFO)) + LOG.info("Interrupted while waiting for service"); + Thread.currentThread().interrupt(); + } + } + }); + } + + private void updateContactList(Collection<Contact> contacts) { + List<String> names = new ArrayList<String>(contacts.size()); + for(Contact c : contacts) names.add(c.getName()); + Collections.sort(names); + adapter.clear(); + for(String name : names) adapter.add(name); } } diff --git a/briar-api/src/net/sf/briar/api/db/DatabaseExecutor.java b/briar-api/src/net/sf/briar/api/db/DatabaseExecutor.java index 70e1de34b720365b52f16f70985cf0de2d7d0f30..82da7a7277bd4f4f2f51f11f9021e7a6ee98fc68 100644 --- a/briar-api/src/net/sf/briar/api/db/DatabaseExecutor.java +++ b/briar-api/src/net/sf/briar/api/db/DatabaseExecutor.java @@ -1,5 +1,6 @@ package net.sf.briar.api.db; +import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.RetentionPolicy.RUNTIME; @@ -10,6 +11,6 @@ import com.google.inject.BindingAnnotation; /** Annotation for injecting the executor for database tasks. */ @BindingAnnotation -@Target({ PARAMETER }) +@Target({ FIELD, PARAMETER }) @Retention(RUNTIME) public @interface DatabaseExecutor {}