Create an identity at startup if the database doesn't exist.

This commit is contained in:
akwizgran
2013-04-08 16:01:52 +01:00
parent ce7e9e73c9
commit de472ba2a6
47 changed files with 934 additions and 419 deletions

View File

@@ -56,7 +56,7 @@ public class BriarService extends RoboService {
b.setContentIntent(pi);
b.setOngoing(true);
startForeground(1, b.build());
// Start the services in the background thread
// Start the services in a background thread
new Thread() {
@Override
public void run() {
@@ -92,8 +92,11 @@ public class BriarService extends RoboService {
private void startServices() {
try {
if(LOG.isLoggable(INFO)) LOG.info("Starting");
db.open(false);
if(LOG.isLoggable(INFO)) LOG.info("Database opened");
boolean reopened = db.open();
if(LOG.isLoggable(INFO)) {
if(reopened) LOG.info("Database reopened");
else LOG.info("Database created");
}
keyManager.start();
if(LOG.isLoggable(INFO)) LOG.info("Key manager started");
int pluginsStarted = pluginManager.start(this);

View File

@@ -3,9 +3,12 @@ package net.sf.briar.android;
import static android.view.Gravity.CENTER;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_MATCH;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
import net.sf.briar.R;
@@ -14,7 +17,11 @@ import net.sf.briar.android.BriarService.BriarServiceConnection;
import net.sf.briar.android.contact.ContactListActivity;
import net.sf.briar.android.groups.GroupListActivity;
import net.sf.briar.android.messages.ConversationListActivity;
import net.sf.briar.android.widgets.CommonLayoutParams;
import net.sf.briar.api.LocalAuthor;
import net.sf.briar.api.android.DatabaseUiExecutor;
import net.sf.briar.api.android.ReferenceManager;
import net.sf.briar.api.db.DatabaseComponent;
import net.sf.briar.api.db.DbException;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
@@ -28,6 +35,8 @@ import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import com.google.inject.Inject;
public class HomeScreenActivity extends BriarActivity {
private static final Logger LOG =
@@ -35,163 +44,49 @@ public class HomeScreenActivity extends BriarActivity {
private final BriarServiceConnection serviceConnection =
new BriarServiceConnection();
private final List<Button> buttons = new ArrayList<Button>();
public HomeScreenActivity() {
super();
}
@Inject private ReferenceManager referenceManager = null;
@Inject @DatabaseUiExecutor private Executor dbUiExecutor = null;
// Fields that are accessed from background threads must be volatile
@Inject private volatile DatabaseComponent db = null;
@Override
public void onCreate(Bundle state) {
super.onCreate(null);
if(LOG.isLoggable(INFO)) LOG.info("Created");
// If this activity was launched from the notification bar, quit
if(getIntent().getBooleanExtra("net.sf.briar.QUIT", false)) {
Intent i = getIntent();
boolean quit = i.getBooleanExtra("net.sf.briar.QUIT", false);
long handle = i.getLongExtra("net.sf.briar.LOCAL_AUTHOR_HANDLE", -1);
if(quit) {
// The activity was launched from the notification bar
showSpinner();
quit();
} else if(handle != -1) {
// The activity was launched from the setup wizard
showSpinner();
storeLocalAuthor(referenceManager.removeReference(handle,
LocalAuthor.class));
} else {
ListView.LayoutParams matchParent =
new ListView.LayoutParams(MATCH_PARENT, MATCH_PARENT);
Button contactsButton = new Button(this);
contactsButton.setLayoutParams(matchParent);
contactsButton.setBackgroundResource(0);
contactsButton.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.social_person, 0, 0);
contactsButton.setText(R.string.contact_list_button);
contactsButton.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
startActivity(new Intent(HomeScreenActivity.this,
ContactListActivity.class));
}
});
buttons.add(contactsButton);
Button messagesButton = new Button(this);
messagesButton.setLayoutParams(matchParent);
messagesButton.setBackgroundResource(0);
messagesButton.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.content_email, 0, 0);
messagesButton.setText(R.string.messages_button);
messagesButton.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
startActivity(new Intent(HomeScreenActivity.this,
ConversationListActivity.class));
}
});
buttons.add(messagesButton);
Button groupsButton = new Button(this);
groupsButton.setLayoutParams(matchParent);
groupsButton.setBackgroundResource(0);
groupsButton.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.social_chat, 0, 0);
groupsButton.setText(R.string.groups_button);
groupsButton.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
Intent i = new Intent(HomeScreenActivity.this,
GroupListActivity.class);
i.putExtra("net.sf.briar.RESTRICTED", false);
i.putExtra("net.sf.briar.TITLE",
getResources().getString(R.string.groups_title));
startActivity(i);
}
});
buttons.add(groupsButton);
Button blogsButton = new Button(this);
blogsButton.setLayoutParams(matchParent);
blogsButton.setBackgroundResource(0);
blogsButton.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.social_blog, 0, 0);
blogsButton.setText(R.string.blogs_button);
blogsButton.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
Intent i = new Intent(HomeScreenActivity.this,
GroupListActivity.class);
i.putExtra("net.sf.briar.RESTRICTED", true);
i.putExtra("net.sf.briar.TITLE",
getResources().getString(R.string.blogs_title));
startActivity(i);
}
});
buttons.add(blogsButton);
Button syncButton = new Button(this);
syncButton.setLayoutParams(matchParent);
syncButton.setBackgroundResource(0);
syncButton.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.navigation_refresh, 0, 0);
syncButton.setText(R.string.synchronize_button);
syncButton.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
// FIXME: Hook this button up to an activity
}
});
buttons.add(syncButton);
Button quitButton = new Button(this);
quitButton.setLayoutParams(matchParent);
quitButton.setBackgroundResource(0);
quitButton.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.device_access_accounts, 0, 0);
quitButton.setText(R.string.quit_button);
quitButton.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
quit();
}
});
buttons.add(quitButton);
GridView grid = new GridView(this);
grid.setLayoutParams(matchParent);
grid.setGravity(CENTER);
grid.setPadding(5, 5, 5, 5);
grid.setBackgroundColor(getResources().getColor(
R.color.home_screen_background));
grid.setNumColumns(2);
grid.setAdapter(new BaseAdapter() {
public int getCount() {
return buttons.size();
}
public Object getItem(int position) {
return buttons.get(position);
}
public long getItemId(int position) {
return 0;
}
public View getView(int position, View convertView,
ViewGroup parent) {
return buttons.get(position);
}
});
setContentView(grid);
// The activity was launched from the splash screen
showButtons();
}
// 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();
unbindService(serviceConnection);
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);
}
private void quit() {
LinearLayout layout = new LinearLayout(this);
layout.setLayoutParams(CommonLayoutParams.MATCH_MATCH);
layout.setGravity(CENTER);
ProgressBar spinner = new ProgressBar(this);
spinner.setIndeterminate(true);
layout.addView(spinner);
setContentView(layout);
new Thread() {
@Override
public void run() {
@@ -204,19 +99,172 @@ public class HomeScreenActivity extends BriarActivity {
if(LOG.isLoggable(INFO)) LOG.info("Shutting down service");
service.shutdown();
service.waitForShutdown();
// Finish the activity and kill the JVM
runOnUiThread(new Runnable() {
public void run() {
finish();
if(LOG.isLoggable(INFO)) LOG.info("Exiting");
System.exit(0);
}
});
} catch(InterruptedException e) {
if(LOG.isLoggable(INFO))
LOG.info("Interrupted while waiting for service");
}
// Finish the activity and kill the JVM
runOnUiThread(new Runnable() {
public void run() {
finish();
if(LOG.isLoggable(INFO)) LOG.info("Exiting");
System.exit(0);
}
});
}
}.start();
}
private void storeLocalAuthor(final LocalAuthor a) {
dbUiExecutor.execute(new Runnable() {
public void run() {
try {
serviceConnection.waitForStartup();
db.addLocalAuthor(a);
runOnUiThread(new Runnable() {
public void run() {
showButtons();
}
});
} 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 showButtons() {
ListView.LayoutParams matchMatch =
new ListView.LayoutParams(MATCH_PARENT, MATCH_PARENT);
final List<Button> buttons = new ArrayList<Button>();
Button contactsButton = new Button(this);
contactsButton.setLayoutParams(matchMatch);
contactsButton.setBackgroundResource(0);
contactsButton.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.social_person, 0, 0);
contactsButton.setText(R.string.contact_list_button);
contactsButton.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
startActivity(new Intent(HomeScreenActivity.this,
ContactListActivity.class));
}
});
buttons.add(contactsButton);
Button messagesButton = new Button(this);
messagesButton.setLayoutParams(matchMatch);
messagesButton.setBackgroundResource(0);
messagesButton.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.content_email, 0, 0);
messagesButton.setText(R.string.messages_button);
messagesButton.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
startActivity(new Intent(HomeScreenActivity.this,
ConversationListActivity.class));
}
});
buttons.add(messagesButton);
Button groupsButton = new Button(this);
groupsButton.setLayoutParams(matchMatch);
groupsButton.setBackgroundResource(0);
groupsButton.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.social_chat, 0, 0);
groupsButton.setText(R.string.groups_button);
groupsButton.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
Intent i = new Intent(HomeScreenActivity.this,
GroupListActivity.class);
i.putExtra("net.sf.briar.RESTRICTED", false);
i.putExtra("net.sf.briar.TITLE",
getResources().getString(R.string.groups_title));
startActivity(i);
}
});
buttons.add(groupsButton);
Button blogsButton = new Button(this);
blogsButton.setLayoutParams(matchMatch);
blogsButton.setBackgroundResource(0);
blogsButton.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.social_blog, 0, 0);
blogsButton.setText(R.string.blogs_button);
blogsButton.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
Intent i = new Intent(HomeScreenActivity.this,
GroupListActivity.class);
i.putExtra("net.sf.briar.RESTRICTED", true);
i.putExtra("net.sf.briar.TITLE",
getResources().getString(R.string.blogs_title));
startActivity(i);
}
});
buttons.add(blogsButton);
Button syncButton = new Button(this);
syncButton.setLayoutParams(matchMatch);
syncButton.setBackgroundResource(0);
syncButton.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.navigation_refresh, 0, 0);
syncButton.setText(R.string.synchronize_button);
syncButton.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
// FIXME: Hook this button up to an activity
}
});
buttons.add(syncButton);
Button quitButton = new Button(this);
quitButton.setLayoutParams(matchMatch);
quitButton.setBackgroundResource(0);
quitButton.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.device_access_accounts, 0, 0);
quitButton.setText(R.string.quit_button);
quitButton.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
quit();
}
});
buttons.add(quitButton);
GridView grid = new GridView(this);
grid.setLayoutParams(matchMatch);
grid.setGravity(CENTER);
grid.setPadding(5, 5, 5, 5);
grid.setBackgroundColor(getResources().getColor(
R.color.home_screen_background));
grid.setNumColumns(2);
grid.setAdapter(new BaseAdapter() {
public int getCount() {
return buttons.size();
}
public Object getItem(int position) {
return buttons.get(position);
}
public long getItemId(int position) {
return 0;
}
public View getView(int position, View convertView,
ViewGroup parent) {
return buttons.get(position);
}
});
setContentView(grid);
}
@Override
public void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
}
}

View File

@@ -1,36 +1,76 @@
package net.sf.briar.android;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import net.sf.briar.R;
import net.sf.briar.api.Author;
import net.sf.briar.api.LocalAuthor;
import android.content.Context;
import android.content.res.Resources;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.SpinnerAdapter;
import android.widget.TextView;
public class LocalAuthorSpinnerAdapter extends ArrayAdapter<LocalAuthor>
public class LocalAuthorSpinnerAdapter extends BaseAdapter
implements SpinnerAdapter {
public LocalAuthorSpinnerAdapter(Context context) {
super(context, android.R.layout.simple_spinner_item,
new ArrayList<LocalAuthor>());
private final Context ctx;
private final List<LocalAuthor> list = new ArrayList<LocalAuthor>();
public LocalAuthorSpinnerAdapter(Context ctx) {
this.ctx = ctx;
}
public void add(LocalAuthor a) {
list.add(a);
notifyDataSetChanged();
}
public void clear() {
list.clear();
notifyDataSetChanged();
}
public int getCount() {
return list.size() + 1;
}
public LocalAuthor getItem(int position) {
if(position == list.size()) return null;
return list.get(position);
}
public long getItemId(int position) {
return android.R.layout.simple_spinner_item;
}
public void sort(Comparator<Author> comparator) {
Collections.sort(list, comparator);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView name = new TextView(getContext());
Log.i("Briar", "getView: " + position);
TextView name = new TextView(ctx);
name.setTextSize(18);
name.setMaxLines(1);
name.setPadding(10, 10, 10, 10);
name.setText(getItem(position).getName());
Resources res = ctx.getResources();
int pad = res.getInteger(R.integer.spinner_padding);
name.setPadding(pad, pad, pad, pad);
if(position == list.size()) name.setText(R.string.create_identity_item);
else name.setText(list.get(position).getName());
return name;
}
@Override
public View getDropDownView(int position, View convertView,
ViewGroup parent) {
Log.i("Briar", "getDropDownView: " + position);
return getView(position, convertView, parent);
}
}

View File

@@ -0,0 +1,138 @@
package net.sf.briar.android;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.view.Gravity.CENTER;
import static android.view.Gravity.CENTER_HORIZONTAL;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static android.view.inputmethod.InputMethodManager.HIDE_IMPLICIT_ONLY;
import static android.widget.LinearLayout.VERTICAL;
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_MATCH;
import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP;
import java.io.IOException;
import java.security.KeyPair;
import java.util.concurrent.Executor;
import net.sf.briar.R;
import net.sf.briar.api.AuthorFactory;
import net.sf.briar.api.LocalAuthor;
import net.sf.briar.api.android.ReferenceManager;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.crypto.CryptoExecutor;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import com.google.inject.Inject;
public class SetupActivity extends BriarActivity
implements OnEditorActionListener, OnClickListener {
@Inject @CryptoExecutor private Executor cryptoExecutor;
private EditText nicknameEntry = null;
private Button createButton = null;
private ProgressBar progress = null;
// Fields that are accessed from background threads must be volatile
@Inject private volatile CryptoComponent crypto;
@Inject private volatile AuthorFactory authorFactory;
@Inject private volatile ReferenceManager referenceManager;
@Override
public void onCreate(Bundle state) {
super.onCreate(null);
LinearLayout layout = new LinearLayout(this);
layout.setLayoutParams(MATCH_MATCH);
layout.setOrientation(VERTICAL);
layout.setGravity(CENTER_HORIZONTAL);
TextView chooseNickname = new TextView(this);
chooseNickname.setGravity(CENTER);
chooseNickname.setTextSize(18);
chooseNickname.setPadding(10, 10, 10, 10);
chooseNickname.setText(R.string.choose_nickname);
layout.addView(chooseNickname);
nicknameEntry = new EditText(this);
nicknameEntry.setTextSize(18);
nicknameEntry.setMaxLines(1);
nicknameEntry.setPadding(10, 10, 10, 10);
nicknameEntry.setOnEditorActionListener(this);
layout.addView(nicknameEntry);
createButton = new Button(this);
createButton.setLayoutParams(WRAP_WRAP);
createButton.setText(R.string.create_button);
createButton.setOnClickListener(this);
layout.addView(createButton);
progress = new ProgressBar(this);
progress.setLayoutParams(WRAP_WRAP);
progress.setIndeterminate(true);
progress.setVisibility(GONE);
layout.addView(progress);
setContentView(layout);
}
public boolean onEditorAction(TextView textView, int actionId, KeyEvent e) {
validateNickname();
return true;
}
public void onClick(View view) {
if(!validateNickname()) return;
final String nickname = nicknameEntry.getText().toString();
// Replace the button with a progress bar
createButton.setVisibility(GONE);
progress.setVisibility(VISIBLE);
// Create the identity in a background thread
cryptoExecutor.execute(new Runnable() {
public void run() {
KeyPair keyPair = crypto.generateSignatureKeyPair();
final byte[] publicKey = keyPair.getPublic().getEncoded();
final byte[] privateKey = keyPair.getPrivate().getEncoded();
LocalAuthor a;
try {
a = authorFactory.createLocalAuthor(nickname, publicKey,
privateKey);
} catch(IOException e) {
throw new RuntimeException(e);
}
showHomeScreen(referenceManager.putReference(a,
LocalAuthor.class));
}
});
}
private void showHomeScreen(final long handle) {
runOnUiThread(new Runnable() {
public void run() {
Intent i = new Intent(SetupActivity.this,
HomeScreenActivity.class);
i.putExtra("net.sf.briar.LOCAL_AUTHOR_HANDLE", handle);
i.setFlags(FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
finish();
}
});
}
private boolean validateNickname() {
if(nicknameEntry.getText().toString().equals("")) return false;
// Hide the soft keyboard
Object o = getSystemService(INPUT_METHOD_SERVICE);
((InputMethodManager) o).toggleSoftInput(HIDE_IMPLICIT_ONLY, 0);
return true;
}
}

View File

@@ -1,15 +1,18 @@
package net.sf.briar.android;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
import static android.view.Gravity.CENTER;
import net.sf.briar.android.widgets.CommonLayoutParams;
import net.sf.briar.api.db.DatabaseConfig;
import roboguice.RoboGuice;
import roboguice.activity.RoboSplashActivity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import com.google.inject.Injector;
public class SplashScreenActivity extends RoboSplashActivity {
public SplashScreenActivity() {
@@ -30,8 +33,15 @@ public class SplashScreenActivity extends RoboSplashActivity {
}
protected void startNextActivity() {
Intent i = new Intent(this, HomeScreenActivity.class);
i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME);
startActivity(i);
Injector guice = RoboGuice.getBaseApplicationInjector(getApplication());
if(guice.getInstance(DatabaseConfig.class).databaseExists()) {
Intent i = new Intent(this, HomeScreenActivity.class);
i.setFlags(FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
} else {
Intent i = new Intent(this, SetupActivity.class);
i.setFlags(FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
}
}
}

View File

@@ -1,9 +1,14 @@
package net.sf.briar.android.contact;
import static android.view.Gravity.CENTER;
import static android.view.Gravity.CENTER_HORIZONTAL;
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 static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_MATCH;
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_WRAP;
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_WRAP_1;
import java.util.Collection;
import java.util.Comparator;
@@ -15,8 +20,8 @@ import net.sf.briar.android.BriarActivity;
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.CommonLayoutParams;
import net.sf.briar.android.widgets.HorizontalBorder;
import net.sf.briar.android.widgets.HorizontalSpace;
import net.sf.briar.api.Contact;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.android.DatabaseUiExecutor;
@@ -50,7 +55,7 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
@Inject private ConnectionRegistry connectionRegistry;
private ContactListAdapter adapter = null;
// Fields that are accessed from DB threads must be volatile
// Fields that are accessed from background threads must be volatile
@Inject private volatile DatabaseComponent db;
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
@@ -58,33 +63,37 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
public void onCreate(Bundle state) {
super.onCreate(null);
LinearLayout layout = new LinearLayout(this);
layout.setLayoutParams(CommonLayoutParams.MATCH_MATCH);
layout.setLayoutParams(MATCH_MATCH);
layout.setOrientation(VERTICAL);
layout.setGravity(CENTER_HORIZONTAL);
adapter = new ContactListAdapter(this);
ListView list = new ListView(this);
// Give me all the width and all the unused height
list.setLayoutParams(CommonLayoutParams.MATCH_WRAP_1);
list.setLayoutParams(MATCH_WRAP_1);
list.setAdapter(adapter);
list.setOnItemClickListener(adapter);
layout.addView(list);
layout.addView(new HorizontalBorder(this));
LinearLayout footer = new LinearLayout(this);
footer.setLayoutParams(MATCH_WRAP);
footer.setOrientation(HORIZONTAL);
footer.setGravity(CENTER);
footer.addView(new HorizontalSpace(this));
ImageButton addContactButton = new ImageButton(this);
addContactButton.setBackgroundResource(0);
addContactButton.setImageResource(R.drawable.social_add_person);
addContactButton.setOnClickListener(this);
layout.addView(addContactButton);
footer.addView(addContactButton);
footer.addView(new HorizontalSpace(this));
layout.addView(footer);
setContentView(layout);
// Listen for contacts being added or removed
db.addListener(this);
// Listen for contacts connecting or disconnecting
connectionRegistry.addListener(this);
// Bind to the service so we can wait for the DB to be opened
// Bind to the service so we can wait for it to start
bindService(new Intent(BriarService.class.getName()),
serviceConnection, 0);
}
@@ -92,6 +101,8 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
@Override
public void onResume() {
super.onResume();
db.addListener(this);
connectionRegistry.addListener(this);
loadContacts();
}
@@ -133,10 +144,15 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
}
@Override
public void onDestroy() {
super.onDestroy();
public void onPause() {
super.onPause();
db.removeListener(this);
connectionRegistry.removeListener(this);
}
@Override
public void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
}
@@ -145,7 +161,6 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
}
public void eventOccurred(DatabaseEvent e) {
// These events should be rare, so just reload the list
if(e instanceof ContactAddedEvent) loadContacts();
else if(e instanceof ContactRemovedEvent) loadContacts();
}

View File

@@ -2,11 +2,11 @@ package net.sf.briar.android.contact;
import static android.view.Gravity.CENTER_VERTICAL;
import static android.widget.LinearLayout.HORIZONTAL;
import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP_1;
import java.util.ArrayList;
import net.sf.briar.R;
import net.sf.briar.android.widgets.CommonLayoutParams;
import android.content.Context;
import android.text.Html;
import android.text.format.DateUtils;
@@ -44,7 +44,7 @@ implements OnItemClickListener {
TextView name = new TextView(ctx);
// Give me all the unused width
name.setLayoutParams(CommonLayoutParams.WRAP_WRAP_1);
name.setLayoutParams(WRAP_WRAP_1);
name.setTextSize(18);
name.setMaxLines(1);
name.setPadding(0, 10, 10, 10);

View File

@@ -4,6 +4,8 @@ import static android.view.Gravity.CENTER_HORIZONTAL;
import static android.widget.LinearLayout.VERTICAL;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_MATCH;
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_WRAP_1;
import java.util.Collection;
import java.util.concurrent.Executor;
@@ -14,7 +16,6 @@ import net.sf.briar.android.AscendingHeaderComparator;
import net.sf.briar.android.BriarActivity;
import net.sf.briar.android.BriarService;
import net.sf.briar.android.BriarService.BriarServiceConnection;
import net.sf.briar.android.widgets.CommonLayoutParams;
import net.sf.briar.android.widgets.HorizontalBorder;
import net.sf.briar.api.Author;
import net.sf.briar.api.android.DatabaseUiExecutor;
@@ -55,7 +56,7 @@ OnClickListener, OnItemClickListener {
private GroupAdapter adapter = null;
private ListView list = null;
// Fields that are accessed from DB threads must be volatile
// Fields that are accessed from background threads must be volatile
@Inject private volatile DatabaseComponent db;
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
private volatile GroupId groupId = null;
@@ -66,22 +67,22 @@ OnClickListener, OnItemClickListener {
Intent i = getIntent();
restricted = i.getBooleanExtra("net.sf.briar.RESTRICTED", false);
byte[] id = i.getByteArrayExtra("net.sf.briar.GROUP_ID");
if(id == null) throw new IllegalStateException();
groupId = new GroupId(id);
byte[] b = i.getByteArrayExtra("net.sf.briar.GROUP_ID");
if(b == null) throw new IllegalStateException();
groupId = new GroupId(b);
groupName = i.getStringExtra("net.sf.briar.GROUP_NAME");
if(groupName == null) throw new IllegalStateException();
setTitle(groupName);
LinearLayout layout = new LinearLayout(this);
layout.setLayoutParams(CommonLayoutParams.MATCH_MATCH);
layout.setLayoutParams(MATCH_MATCH);
layout.setOrientation(VERTICAL);
layout.setGravity(CENTER_HORIZONTAL);
adapter = new GroupAdapter(this);
list = new ListView(this);
// Give me all the width and all the unused height
list.setLayoutParams(CommonLayoutParams.MATCH_WRAP_1);
list.setLayoutParams(MATCH_WRAP_1);
list.setAdapter(adapter);
list.setOnItemClickListener(this);
layout.addView(list);
@@ -96,7 +97,7 @@ OnClickListener, OnItemClickListener {
setContentView(layout);
// Bind to the service so we can wait for the DB to be opened
// Bind to the service so we can wait for it to start
bindService(new Intent(BriarService.class.getName()),
serviceConnection, 0);
}
@@ -234,8 +235,6 @@ OnClickListener, OnItemClickListener {
}
i.putExtra("net.sf.briar.CONTENT_TYPE", item.getContentType());
i.putExtra("net.sf.briar.TIMESTAMP", item.getTimestamp());
i.putExtra("net.sf.briar.FIRST", position == 0);
i.putExtra("net.sf.briar.LAST", position == adapter.getCount() - 1);
startActivityForResult(i, position);
}
}

View File

@@ -6,13 +6,13 @@ import static android.view.View.INVISIBLE;
import static android.widget.LinearLayout.HORIZONTAL;
import static android.widget.LinearLayout.VERTICAL;
import static java.text.DateFormat.SHORT;
import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP_1;
import static net.sf.briar.api.messaging.Rating.GOOD;
import static net.sf.briar.api.messaging.Rating.UNRATED;
import java.util.ArrayList;
import net.sf.briar.R;
import net.sf.briar.android.widgets.CommonLayoutParams;
import net.sf.briar.android.widgets.HorizontalSpace;
import net.sf.briar.api.Author;
import net.sf.briar.api.db.GroupMessageHeader;
@@ -39,6 +39,7 @@ class GroupAdapter extends ArrayAdapter<GroupMessageHeader> {
public View getView(int position, View convertView, ViewGroup parent) {
GroupMessageHeader item = getItem(position);
Context ctx = getContext();
// FIXME: Use a RelativeLayout
LinearLayout layout = new LinearLayout(ctx);
layout.setOrientation(HORIZONTAL);
@@ -49,7 +50,7 @@ class GroupAdapter extends ArrayAdapter<GroupMessageHeader> {
LinearLayout innerLayout = new LinearLayout(ctx);
// Give me all the unused width
innerLayout.setLayoutParams(CommonLayoutParams.WRAP_WRAP_1);
innerLayout.setLayoutParams(WRAP_WRAP_1);
innerLayout.setOrientation(VERTICAL);
LinearLayout authorLayout = new LinearLayout(ctx);
@@ -66,7 +67,7 @@ class GroupAdapter extends ArrayAdapter<GroupMessageHeader> {
TextView name = new TextView(ctx);
// Give me all the unused width
name.setLayoutParams(CommonLayoutParams.WRAP_WRAP_1);
name.setLayoutParams(WRAP_WRAP_1);
name.setTextSize(18);
name.setMaxLines(1);
name.setPadding(0, 10, 10, 10);

View File

@@ -6,6 +6,9 @@ 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 static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_MATCH;
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_WRAP;
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_WRAP_1;
import java.util.ArrayList;
import java.util.Collection;
@@ -18,7 +21,6 @@ import net.sf.briar.R;
import net.sf.briar.android.BriarActivity;
import net.sf.briar.android.BriarService;
import net.sf.briar.android.BriarService.BriarServiceConnection;
import net.sf.briar.android.widgets.CommonLayoutParams;
import net.sf.briar.android.widgets.HorizontalBorder;
import net.sf.briar.android.widgets.HorizontalSpace;
import net.sf.briar.api.android.DatabaseUiExecutor;
@@ -56,7 +58,7 @@ implements OnClickListener, DatabaseListener {
private ListView list = null;
private ImageButton newGroupButton = null, composeButton = null;
// Fields that are accessed from DB threads must be volatile
// Fields that are accessed from background threads must be volatile
@Inject private volatile DatabaseComponent db;
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
private volatile boolean restricted = false;
@@ -65,7 +67,7 @@ implements OnClickListener, DatabaseListener {
public void onCreate(Bundle state) {
super.onCreate(null);
LinearLayout layout = new LinearLayout(this);
layout.setLayoutParams(CommonLayoutParams.MATCH_MATCH);
layout.setLayoutParams(MATCH_MATCH);
layout.setOrientation(VERTICAL);
layout.setGravity(CENTER_HORIZONTAL);
@@ -78,7 +80,7 @@ implements OnClickListener, DatabaseListener {
adapter = new GroupListAdapter(this);
list = new ListView(this);
// Give me all the width and all the unused height
list.setLayoutParams(CommonLayoutParams.MATCH_WRAP_1);
list.setLayoutParams(MATCH_WRAP_1);
list.setAdapter(adapter);
list.setOnItemClickListener(adapter);
layout.addView(list);
@@ -86,7 +88,7 @@ implements OnClickListener, DatabaseListener {
layout.addView(new HorizontalBorder(this));
LinearLayout footer = new LinearLayout(this);
footer.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
footer.setLayoutParams(MATCH_WRAP);
footer.setOrientation(HORIZONTAL);
footer.setGravity(CENTER);
footer.addView(new HorizontalSpace(this));
@@ -110,7 +112,7 @@ implements OnClickListener, DatabaseListener {
setContentView(layout);
// Bind to the service so we can wait for the DB to be opened
// Bind to the service so we can wait for it to start
bindService(new Intent(BriarService.class.getName()),
serviceConnection, 0);
}

View File

@@ -4,11 +4,11 @@ import static android.graphics.Typeface.BOLD;
import static android.widget.LinearLayout.HORIZONTAL;
import static android.widget.LinearLayout.VERTICAL;
import static java.text.DateFormat.SHORT;
import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP_1;
import java.util.ArrayList;
import net.sf.briar.R;
import net.sf.briar.android.widgets.CommonLayoutParams;
import net.sf.briar.android.widgets.HorizontalSpace;
import net.sf.briar.util.StringUtils;
import android.content.Context;
@@ -45,7 +45,7 @@ implements OnItemClickListener {
LinearLayout innerLayout = new LinearLayout(ctx);
// Give me all the unused width
innerLayout.setLayoutParams(CommonLayoutParams.WRAP_WRAP_1);
innerLayout.setLayoutParams(WRAP_WRAP_1);
innerLayout.setOrientation(VERTICAL);
TextView name = new TextView(ctx);

View File

@@ -9,6 +9,9 @@ import static android.widget.LinearLayout.VERTICAL;
import static java.text.DateFormat.SHORT;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_WRAP;
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_WRAP_1;
import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP_1;
import static net.sf.briar.api.messaging.Rating.BAD;
import static net.sf.briar.api.messaging.Rating.GOOD;
import static net.sf.briar.api.messaging.Rating.UNRATED;
@@ -21,7 +24,6 @@ import net.sf.briar.R;
import net.sf.briar.android.BriarActivity;
import net.sf.briar.android.BriarService;
import net.sf.briar.android.BriarService.BriarServiceConnection;
import net.sf.briar.android.widgets.CommonLayoutParams;
import net.sf.briar.android.widgets.HorizontalBorder;
import net.sf.briar.android.widgets.HorizontalSpace;
import net.sf.briar.api.AuthorId;
@@ -70,7 +72,7 @@ implements OnClickListener {
private ImageButton replyButton = null;
private TextView content = null;
// Fields that are accessed from DB threads must be volatile
// Fields that are accessed from background threads must be volatile
@Inject private volatile DatabaseComponent db;
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
private volatile MessageId messageId = null;
@@ -81,19 +83,19 @@ implements OnClickListener {
super.onCreate(null);
Intent i = getIntent();
byte[] id = i.getByteArrayExtra("net.sf.briar.GROUP_ID");
if(id == null) throw new IllegalStateException();
groupId = new GroupId(id);
byte[] b = i.getByteArrayExtra("net.sf.briar.GROUP_ID");
if(b == null) throw new IllegalStateException();
groupId = new GroupId(b);
String groupName = i.getStringExtra("net.sf.briar.GROUP_NAME");
if(groupName == null) throw new IllegalStateException();
setTitle(groupName);
id = i.getByteArrayExtra("net.sf.briar.MESSAGE_ID");
if(id == null) throw new IllegalStateException();
messageId = new MessageId(id);
b = i.getByteArrayExtra("net.sf.briar.MESSAGE_ID");
if(b == null) throw new IllegalStateException();
messageId = new MessageId(b);
String authorName = null;
id = i.getByteArrayExtra("net.sf.briar.AUTHOR_ID");
if(id != null) {
authorId = new AuthorId(id);
b = i.getByteArrayExtra("net.sf.briar.AUTHOR_ID");
if(b != null) {
authorId = new AuthorId(b);
authorName = i.getStringExtra("net.sf.briar.AUTHOR_NAME");
if(authorName == null) throw new IllegalStateException();
String r = i.getStringExtra("net.sf.briar.RATING");
@@ -103,8 +105,6 @@ implements OnClickListener {
if(contentType == null) throw new IllegalStateException();
long timestamp = i.getLongExtra("net.sf.briar.TIMESTAMP", -1);
if(timestamp == -1) throw new IllegalStateException();
boolean first = i.getBooleanExtra("net.sf.briar.FIRST", false);
boolean last = i.getBooleanExtra("net.sf.briar.LAST", false);
if(state != null && bundleEncrypter.decrypt(state)) {
read = state.getBoolean("net.sf.briar.READ");
@@ -114,12 +114,12 @@ implements OnClickListener {
}
LinearLayout layout = new LinearLayout(this);
layout.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
layout.setLayoutParams(MATCH_WRAP);
layout.setOrientation(VERTICAL);
ScrollView scrollView = new ScrollView(this);
// Give me all the width and all the unused height
scrollView.setLayoutParams(CommonLayoutParams.MATCH_WRAP_1);
scrollView.setLayoutParams(MATCH_WRAP_1);
LinearLayout message = new LinearLayout(this);
message.setOrientation(VERTICAL);
@@ -127,7 +127,7 @@ implements OnClickListener {
message.setBackgroundColor(res.getColor(R.color.content_background));
LinearLayout header = new LinearLayout(this);
header.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
header.setLayoutParams(MATCH_WRAP);
header.setOrientation(HORIZONTAL);
header.setGravity(CENTER_VERTICAL);
@@ -140,7 +140,7 @@ implements OnClickListener {
TextView author = new TextView(this);
// Give me all the unused width
author.setLayoutParams(CommonLayoutParams.WRAP_WRAP_1);
author.setLayoutParams(WRAP_WRAP_1);
author.setTextSize(18);
author.setMaxLines(1);
author.setPadding(10, 10, 10, 10);
@@ -174,7 +174,7 @@ implements OnClickListener {
layout.addView(new HorizontalBorder(this));
LinearLayout footer = new LinearLayout(this);
footer.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
footer.setLayoutParams(MATCH_WRAP);
footer.setOrientation(HORIZONTAL);
footer.setGravity(CENTER);
@@ -207,7 +207,6 @@ implements OnClickListener {
prevButton.setBackgroundResource(0);
prevButton.setImageResource(R.drawable.navigation_previous_item);
prevButton.setOnClickListener(this);
prevButton.setEnabled(!first);
footer.addView(prevButton);
footer.addView(new HorizontalSpace(this));
@@ -215,7 +214,6 @@ implements OnClickListener {
nextButton.setBackgroundResource(0);
nextButton.setImageResource(R.drawable.navigation_next_item);
nextButton.setOnClickListener(this);
nextButton.setEnabled(!last);
footer.addView(nextButton);
footer.addView(new HorizontalSpace(this));
@@ -228,7 +226,7 @@ implements OnClickListener {
setContentView(layout);
// Bind to the service so we can wait for the DB to be opened
// Bind to the service so we can wait for it to start
bindService(new Intent(BriarService.class.getName()),
serviceConnection, 0);
}

View File

@@ -5,6 +5,7 @@ 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 static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_WRAP;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
@@ -22,7 +23,6 @@ import net.sf.briar.android.BriarActivity;
import net.sf.briar.android.BriarService;
import net.sf.briar.android.BriarService.BriarServiceConnection;
import net.sf.briar.android.LocalAuthorSpinnerAdapter;
import net.sf.briar.android.widgets.CommonLayoutParams;
import net.sf.briar.android.widgets.HorizontalSpace;
import net.sf.briar.api.LocalAuthor;
import net.sf.briar.api.android.BundleEncrypter;
@@ -65,7 +65,7 @@ implements OnItemSelectedListener, OnClickListener {
private ImageButton sendButton = null;
private EditText content = null;
// Fields that are accessed from DB threads must be volatile
// Fields that are accessed from background threads must be volatile
@Inject private volatile DatabaseComponent db;
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
@Inject private volatile MessageFactory messageFactory;
@@ -81,17 +81,17 @@ implements OnItemSelectedListener, OnClickListener {
Intent i = getIntent();
restricted = i.getBooleanExtra("net.sf.briar.RESTRICTED", false);
byte[] id = i.getByteArrayExtra("net.sf.briar.GROUP_ID");
if(id != null) groupId = new GroupId(id);
id = i.getByteArrayExtra("net.sf.briar.PARENT_ID");
if(id != null) parentId = new MessageId(id);
byte[] b = i.getByteArrayExtra("net.sf.briar.GROUP_ID");
if(b != null) groupId = new GroupId(b);
b = i.getByteArrayExtra("net.sf.briar.PARENT_ID");
if(b != null) parentId = new MessageId(b);
LinearLayout layout = new LinearLayout(this);
layout.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
layout.setLayoutParams(MATCH_WRAP);
layout.setOrientation(VERTICAL);
LinearLayout header = new LinearLayout(this);
header.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
header.setLayoutParams(MATCH_WRAP);
header.setOrientation(HORIZONTAL);
header.setGravity(CENTER_VERTICAL);
@@ -103,8 +103,8 @@ implements OnItemSelectedListener, OnClickListener {
fromAdapter = new LocalAuthorSpinnerAdapter(this);
fromSpinner = new Spinner(this);
fromSpinner.setAdapter(fromAdapter);
fromSpinner.setOnItemSelectedListener(this);
loadLocalAuthorList();
header.addView(fromSpinner);
header.addView(new HorizontalSpace(this));
@@ -118,7 +118,7 @@ implements OnItemSelectedListener, OnClickListener {
layout.addView(header);
header = new LinearLayout(this);
header.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
header.setLayoutParams(MATCH_WRAP);
header.setOrientation(HORIZONTAL);
header.setGravity(CENTER_VERTICAL);
@@ -132,7 +132,6 @@ implements OnItemSelectedListener, OnClickListener {
toSpinner = new Spinner(this);
toSpinner.setAdapter(toAdapter);
toSpinner.setOnItemSelectedListener(this);
loadGroupList();
header.addView(toSpinner);
layout.addView(header);
@@ -146,17 +145,24 @@ implements OnItemSelectedListener, OnClickListener {
setContentView(layout);
// Bind to the service so we can wait for the DB to be opened
// Bind to the service so we can wait for it to start
bindService(new Intent(BriarService.class.getName()),
serviceConnection, 0);
}
private void loadLocalAuthorList() {
@Override
public void onResume() {
super.onResume();
loadLocalAuthors();
loadGroups();
}
private void loadLocalAuthors() {
dbUiExecutor.execute(new Runnable() {
public void run() {
try {
serviceConnection.waitForStartup();
displayLocalAuthorList(db.getLocalAuthors());
displayLocalAuthors(db.getLocalAuthors());
} catch(DbException e) {
if(LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
@@ -168,7 +174,7 @@ implements OnItemSelectedListener, OnClickListener {
});
}
private void displayLocalAuthorList(
private void displayLocalAuthors(
final Collection<LocalAuthor> localAuthors) {
runOnUiThread(new Runnable() {
public void run() {
@@ -179,7 +185,7 @@ implements OnItemSelectedListener, OnClickListener {
});
}
private void loadGroupList() {
private void loadGroups() {
dbUiExecutor.execute(new Runnable() {
public void run() {
try {
@@ -192,7 +198,7 @@ implements OnItemSelectedListener, OnClickListener {
if(!g.isRestricted()) groups.add(g);
}
groups = Collections.unmodifiableList(groups);
displayGroupList(groups);
displayGroups(groups);
} catch(DbException e) {
if(LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
@@ -204,7 +210,7 @@ implements OnItemSelectedListener, OnClickListener {
});
}
private void displayGroupList(final Collection<Group> groups) {
private void displayGroups(final Collection<Group> groups) {
runOnUiThread(new Runnable() {
public void run() {
int index = -1;
@@ -257,8 +263,8 @@ implements OnItemSelectedListener, OnClickListener {
public void onClick(View view) {
if(group == null) throw new IllegalStateException();
try {
storeMessage(localAuthor, group,
content.getText().toString().getBytes("UTF-8"));
byte[] b = content.getText().toString().getBytes("UTF-8");
storeMessage(localAuthor, group, b);
} catch(UnsupportedEncodingException e) {
throw new RuntimeException(e);
}

View File

@@ -32,10 +32,15 @@ public class HelloWorldModule extends AbstractModule {
@Provides @Singleton
DatabaseConfig getDatabaseConfig(final Application app) {
final File dir = app.getApplicationContext().getDir("db", MODE_PRIVATE);
return new DatabaseConfig() {
public File getDataDirectory() {
return app.getApplicationContext().getDir("db", MODE_PRIVATE);
public boolean databaseExists() {
return dir.isDirectory() && dir.listFiles().length > 0;
}
public File getDatabaseDirectory() {
return dir;
}
public char[] getPassword() {

View File

@@ -0,0 +1,165 @@
package net.sf.briar.android.identity;
import static android.view.Gravity.CENTER;
import static android.view.Gravity.CENTER_HORIZONTAL;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static android.view.inputmethod.InputMethodManager.HIDE_IMPLICIT_ONLY;
import static android.widget.LinearLayout.VERTICAL;
import static java.util.logging.Level.WARNING;
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_MATCH;
import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP;
import java.io.IOException;
import java.security.KeyPair;
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.BriarServiceConnection;
import net.sf.briar.api.AuthorFactory;
import net.sf.briar.api.LocalAuthor;
import net.sf.briar.api.android.DatabaseUiExecutor;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.crypto.CryptoExecutor;
import net.sf.briar.api.db.DatabaseComponent;
import net.sf.briar.api.db.DbException;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import com.google.inject.Inject;
public class CreateIdentityActivity extends BriarActivity
implements OnEditorActionListener, OnClickListener {
private static final Logger LOG =
Logger.getLogger(CreateIdentityActivity.class.getName());
private final BriarServiceConnection serviceConnection =
new BriarServiceConnection();
@Inject @CryptoExecutor private Executor cryptoExecutor;
private EditText nicknameEntry = null;
private Button createButton = null;
private ProgressBar progress = null;
// Fields that are accessed from background threads must be volatile
@Inject private volatile CryptoComponent crypto;
@Inject private volatile AuthorFactory authorFactory;
@Inject private volatile DatabaseComponent db;
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
@Override
public void onCreate(Bundle state) {
super.onCreate(null);
LinearLayout layout = new LinearLayout(this);
layout.setLayoutParams(MATCH_MATCH);
layout.setOrientation(VERTICAL);
layout.setGravity(CENTER_HORIZONTAL);
TextView chooseNickname = new TextView(this);
chooseNickname.setGravity(CENTER);
chooseNickname.setTextSize(18);
chooseNickname.setPadding(10, 10, 10, 10);
chooseNickname.setText(R.string.choose_nickname);
layout.addView(chooseNickname);
nicknameEntry = new EditText(this);
nicknameEntry.setTextSize(18);
nicknameEntry.setMaxLines(1);
nicknameEntry.setPadding(10, 10, 10, 10);
nicknameEntry.setOnEditorActionListener(this);
layout.addView(nicknameEntry);
createButton = new Button(this);
createButton.setLayoutParams(WRAP_WRAP);
createButton.setText(R.string.create_button);
createButton.setOnClickListener(this);
layout.addView(createButton);
progress = new ProgressBar(this);
progress.setLayoutParams(WRAP_WRAP);
progress.setIndeterminate(true);
progress.setVisibility(GONE);
layout.addView(progress);
setContentView(layout);
// Bind to the service so we can wait for it to start
bindService(new Intent(BriarService.class.getName()),
serviceConnection, 0);
}
@Override
public void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
}
public boolean onEditorAction(TextView textView, int actionId, KeyEvent e) {
validateNickname();
return true;
}
public void onClick(View view) {
if(!validateNickname()) return;
final String nickname = nicknameEntry.getText().toString();
// Replace the button with a progress bar
createButton.setVisibility(GONE);
progress.setVisibility(VISIBLE);
// Create the identity in a background thread
cryptoExecutor.execute(new Runnable() {
public void run() {
KeyPair keyPair = crypto.generateSignatureKeyPair();
final byte[] publicKey = keyPair.getPublic().getEncoded();
final byte[] privateKey = keyPair.getPrivate().getEncoded();
LocalAuthor a;
try {
a = authorFactory.createLocalAuthor(nickname, publicKey,
privateKey);
} catch(IOException e) {
throw new RuntimeException(e);
}
storeLocalAuthor(a);
}
});
}
private void storeLocalAuthor(final LocalAuthor a) {
dbUiExecutor.execute(new Runnable() {
public void run() {
try {
db.addLocalAuthor(a);
} catch(DbException e) {
if(LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
}
runOnUiThread(new Runnable() {
public void run() {
finish();
}
});
}
});
}
private boolean validateNickname() {
if(nicknameEntry.getText().toString().equals("")) return false;
// Hide the soft keyboard
Object o = getSystemService(INPUT_METHOD_SERVICE);
((InputMethodManager) o).toggleSoftInput(HIDE_IMPLICIT_ONLY, 0);
return true;
}
}

View File

@@ -10,6 +10,7 @@ import net.sf.briar.android.AuthorNameComparator;
import net.sf.briar.android.BriarActivity;
import net.sf.briar.android.BriarService;
import net.sf.briar.android.BriarService.BriarServiceConnection;
import net.sf.briar.android.LocalAuthorSpinnerAdapter;
import net.sf.briar.api.AuthorId;
import net.sf.briar.api.LocalAuthor;
import net.sf.briar.api.android.BundleEncrypter;
@@ -24,7 +25,6 @@ import net.sf.briar.api.invitation.InvitationTask;
import net.sf.briar.api.invitation.InvitationTaskFactory;
import android.content.Intent;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import com.google.inject.Inject;
@@ -54,7 +54,7 @@ implements InvitationListener {
private boolean localMatched = false, remoteMatched = false;
private String contactName = null;
// Fields that are accessed from DB threads must be volatile
// Fields that are accessed from background threads must be volatile
@Inject private volatile DatabaseComponent db;
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
@@ -66,8 +66,8 @@ implements InvitationListener {
setView(new NetworkSetupView(this));
} else {
// Restore the activity's state
byte[] id = state.getByteArray("net.sf.briar.LOCAL_AUTHOR_ID");
if(id != null) localAuthorId = new AuthorId(id);
byte[] b = state.getByteArray("net.sf.briar.LOCAL_AUTHOR_ID");
if(b != null) localAuthorId = new AuthorId(b);
networkName = state.getString("net.sf.briar.NETWORK_NAME");
useBluetooth = state.getBoolean("net.sf.briar.USE_BLUETOOTH");
taskHandle = state.getLong("net.sf.briar.TASK_HANDLE", -1);
@@ -131,7 +131,7 @@ implements InvitationListener {
}
}
// Bind to the service so we can wait for the DB to be opened
// Bind to the service so we can wait for it to start
bindService(new Intent(BriarService.class.getName()),
serviceConnection, 0);
}
@@ -162,6 +162,7 @@ implements InvitationListener {
public void onDestroy() {
super.onDestroy();
if(task != null) task.removeListener(this);
unbindService(serviceConnection);
}
void setView(AddContactView view) {
@@ -171,9 +172,9 @@ implements InvitationListener {
}
void reset(AddContactView view) {
// Note: localAuthorId is not reset
task = null;
taskHandle = -1;
localAuthorId = null;
networkName = null;
useBluetooth = false;
localInvitationCode = -1;
@@ -185,12 +186,12 @@ implements InvitationListener {
setView(view);
}
void loadLocalAuthorList(final ArrayAdapter<LocalAuthor> adapter) {
void loadLocalAuthorList(final LocalAuthorSpinnerAdapter adapter) {
dbUiExecutor.execute(new Runnable() {
public void run() {
try {
serviceConnection.waitForStartup();
updateLocalAuthorList(adapter, db.getLocalAuthors());
displayLocalAuthorList(adapter, db.getLocalAuthors());
} catch(DbException e) {
if(LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
@@ -202,7 +203,7 @@ implements InvitationListener {
});
}
private void updateLocalAuthorList(final ArrayAdapter<LocalAuthor> adapter,
private void displayLocalAuthorList(final LocalAuthorSpinnerAdapter adapter,
final Collection<LocalAuthor> localAuthors) {
runOnUiThread(new Runnable() {
public void run() {

View File

@@ -1,7 +1,7 @@
package net.sf.briar.android.invitation;
import static android.view.Gravity.CENTER_HORIZONTAL;
import net.sf.briar.android.widgets.CommonLayoutParams;
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_MATCH;
import android.content.Context;
import android.widget.LinearLayout;
@@ -15,7 +15,7 @@ abstract class AddContactView extends LinearLayout {
void init(AddContactActivity container) {
this.container = container;
setLayoutParams(CommonLayoutParams.MATCH_MATCH);
setLayoutParams(MATCH_MATCH);
setOrientation(VERTICAL);
setGravity(CENTER_HORIZONTAL);
populate();

View File

@@ -3,8 +3,8 @@ package net.sf.briar.android.invitation;
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
import static android.provider.Settings.ACTION_BLUETOOTH_SETTINGS;
import static android.view.Gravity.CENTER;
import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP_1;
import net.sf.briar.R;
import net.sf.briar.android.widgets.CommonLayoutParams;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.Intent;
@@ -34,7 +34,7 @@ public class BluetoothWidget extends LinearLayout implements OnClickListener {
removeAllViews();
Context ctx = getContext();
TextView status = new TextView(ctx);
status.setLayoutParams(CommonLayoutParams.WRAP_WRAP_1);
status.setLayoutParams(WRAP_WRAP_1);
status.setTextSize(14);
status.setPadding(10, 10, 10, 10);
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();

View File

@@ -5,8 +5,8 @@ import static android.text.InputType.TYPE_CLASS_NUMBER;
import static android.view.Gravity.CENTER;
import static android.view.Gravity.CENTER_HORIZONTAL;
import static android.view.inputmethod.InputMethodManager.HIDE_IMPLICIT_ONLY;
import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP;
import net.sf.briar.R;
import net.sf.briar.android.widgets.CommonLayoutParams;
import android.content.Context;
import android.view.KeyEvent;
import android.view.View;
@@ -18,8 +18,8 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
public class CodeEntryWidget extends LinearLayout implements
OnEditorActionListener, OnClickListener {
public class CodeEntryWidget extends LinearLayout
implements OnEditorActionListener, OnClickListener {
private CodeEntryListener listener = null;
private EditText codeEntry = null;
@@ -46,7 +46,7 @@ OnEditorActionListener, OnClickListener {
innerLayout.setGravity(CENTER);
final Button continueButton = new Button(ctx);
continueButton.setLayoutParams(CommonLayoutParams.WRAP_WRAP);
continueButton.setLayoutParams(WRAP_WRAP);
continueButton.setText(R.string.continue_button);
continueButton.setEnabled(false);
continueButton.setOnClickListener(this);

View File

@@ -1,8 +1,8 @@
package net.sf.briar.android.invitation;
import static android.view.Gravity.CENTER;
import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP;
import net.sf.briar.R;
import net.sf.briar.android.widgets.CommonLayoutParams;
import android.content.Context;
import android.view.View;
import android.view.View.OnClickListener;
@@ -44,7 +44,7 @@ implements OnClickListener {
addView(interfering);
Button tryAgainButton = new Button(ctx);
tryAgainButton.setLayoutParams(CommonLayoutParams.WRAP_WRAP);
tryAgainButton.setLayoutParams(WRAP_WRAP);
tryAgainButton.setText(R.string.try_again_button);
tryAgainButton.setOnClickListener(this);
addView(tryAgainButton);

View File

@@ -1,8 +1,8 @@
package net.sf.briar.android.invitation;
import static android.view.Gravity.CENTER;
import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP;
import net.sf.briar.R;
import net.sf.briar.android.widgets.CommonLayoutParams;
import android.content.Context;
import android.view.View;
import android.view.View.OnClickListener;
@@ -54,7 +54,7 @@ implements WifiStateListener, BluetoothStateListener, OnClickListener {
addView(bluetooth);
tryAgainButton = new Button(ctx);
tryAgainButton.setLayoutParams(CommonLayoutParams.WRAP_WRAP);
tryAgainButton.setLayoutParams(WRAP_WRAP);
tryAgainButton.setText(R.string.try_again_button);
tryAgainButton.setOnClickListener(this);
enabledOrDisableTryAgainButton();

View File

@@ -1,8 +1,8 @@
package net.sf.briar.android.invitation;
import static android.view.Gravity.CENTER;
import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP;
import net.sf.briar.R;
import net.sf.briar.android.widgets.CommonLayoutParams;
import android.content.Context;
import android.view.View;
import android.view.View.OnClickListener;
@@ -38,15 +38,15 @@ implements OnClickListener {
addView(innerLayout);
TextView contactName = new TextView(ctx);
contactName.setGravity(CENTER);
contactName.setTextSize(22);
contactName.setPadding(10, 0, 10, 10);
contactName.setText(container.getContactName());
addView(contactName);
Button doneButton = new Button(ctx);
doneButton.setLayoutParams(CommonLayoutParams.WRAP_WRAP);
doneButton.setLayoutParams(WRAP_WRAP);
doneButton.setText(R.string.done_button);
doneButton.setEnabled(false);
doneButton.setOnClickListener(this);
addView(doneButton);
}

View File

@@ -1,10 +1,14 @@
package net.sf.briar.android.invitation;
import static android.view.Gravity.CENTER;
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_WRAP;
import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP;
import net.sf.briar.R;
import net.sf.briar.android.LocalAuthorSpinnerAdapter;
import net.sf.briar.android.widgets.CommonLayoutParams;
import net.sf.briar.android.identity.CreateIdentityActivity;
import net.sf.briar.api.LocalAuthor;
import android.content.Context;
import android.content.Intent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
@@ -31,7 +35,7 @@ OnClickListener {
Context ctx = getContext();
LinearLayout innerLayout = new LinearLayout(ctx);
innerLayout.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
innerLayout.setLayoutParams(MATCH_WRAP);
innerLayout.setOrientation(HORIZONTAL);
innerLayout.setGravity(CENTER);
@@ -58,7 +62,7 @@ OnClickListener {
addView(bluetooth);
continueButton = new Button(ctx);
continueButton.setLayoutParams(CommonLayoutParams.WRAP_WRAP);
continueButton.setLayoutParams(WRAP_WRAP);
continueButton.setText(R.string.continue_button);
continueButton.setOnClickListener(this);
enableOrDisableContinueButton();
@@ -93,7 +97,13 @@ OnClickListener {
public void onItemSelected(AdapterView<?> parent, View view, int position,
long id) {
container.setLocalAuthorId(adapter.getItem(position).getId());
LocalAuthor item = adapter.getItem(position);
if(item == null) {
Intent i = new Intent(container, CreateIdentityActivity.class);
container.startActivity(i);
} else {
container.setLocalAuthorId(item.getId());
}
}
public void onNothingSelected(AdapterView<?> parent) {

View File

@@ -3,8 +3,8 @@ package net.sf.briar.android.invitation;
import static android.content.Context.WIFI_SERVICE;
import static android.provider.Settings.ACTION_WIFI_SETTINGS;
import static android.view.Gravity.CENTER;
import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP_1;
import net.sf.briar.R;
import net.sf.briar.android.widgets.CommonLayoutParams;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.WifiInfo;
@@ -37,7 +37,7 @@ public class WifiWidget extends LinearLayout implements OnClickListener {
TextView status = new TextView(ctx);
status.setTextSize(14);
status.setPadding(10, 10, 10, 10);
status.setLayoutParams(CommonLayoutParams.WRAP_WRAP_1);
status.setLayoutParams(WRAP_WRAP_1);
WifiManager wifi = (WifiManager) ctx.getSystemService(WIFI_SERVICE);
if(wifi == null) {
wifiStateChanged(null);

View File

@@ -4,6 +4,8 @@ import static android.view.Gravity.CENTER_HORIZONTAL;
import static android.widget.LinearLayout.VERTICAL;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_MATCH;
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_WRAP_1;
import java.util.Collection;
import java.util.concurrent.Executor;
@@ -14,9 +16,10 @@ import net.sf.briar.android.AscendingHeaderComparator;
import net.sf.briar.android.BriarActivity;
import net.sf.briar.android.BriarService;
import net.sf.briar.android.BriarService.BriarServiceConnection;
import net.sf.briar.android.widgets.CommonLayoutParams;
import net.sf.briar.android.widgets.HorizontalBorder;
import net.sf.briar.api.AuthorId;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.LocalAuthor;
import net.sf.briar.api.android.DatabaseUiExecutor;
import net.sf.briar.api.db.DatabaseComponent;
import net.sf.briar.api.db.DbException;
@@ -52,10 +55,12 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
private ConversationAdapter adapter = null;
private ListView list = null;
// Fields that are accessed from DB threads must be volatile
// Fields that are accessed from background threads must be volatile
@Inject private volatile DatabaseComponent db;
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
private volatile ContactId contactId = null;
private volatile AuthorId localAuthorId = null;
private volatile String localAuthorName = null;
@Override
public void onCreate(Bundle state) {
@@ -68,16 +73,19 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
contactName = i.getStringExtra("net.sf.briar.CONTACT_NAME");
if(contactName == null) throw new IllegalStateException();
setTitle(contactName);
byte[] b = i.getByteArrayExtra("net.sf.briar.LOCAL_AUTHOR_ID");
if(b == null) throw new IllegalStateException();
localAuthorId = new AuthorId(b);
LinearLayout layout = new LinearLayout(this);
layout.setLayoutParams(CommonLayoutParams.MATCH_MATCH);
layout.setLayoutParams(MATCH_MATCH);
layout.setOrientation(VERTICAL);
layout.setGravity(CENTER_HORIZONTAL);
adapter = new ConversationAdapter(this);
adapter = new ConversationAdapter(this, contactName);
list = new ListView(this);
// Give me all the width and all the unused height
list.setLayoutParams(CommonLayoutParams.MATCH_WRAP_1);
list.setLayoutParams(MATCH_WRAP_1);
list.setAdapter(adapter);
list.setOnItemClickListener(this);
layout.addView(list);
@@ -92,7 +100,7 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
setContentView(layout);
// Bind to the service so we can wait for the DB to be opened
// Bind to the service so we can wait for it to start
bindService(new Intent(BriarService.class.getName()),
serviceConnection, 0);
}
@@ -108,17 +116,16 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
dbUiExecutor.execute(new Runnable() {
public void run() {
try {
// Wait for the service to be bound and started
serviceConnection.waitForStartup();
// Load the headers from the database
long now = System.currentTimeMillis();
LocalAuthor localAuthor = db.getLocalAuthor(localAuthorId);
localAuthorName = localAuthor.getName();
Collection<PrivateMessageHeader> headers =
db.getPrivateMessageHeaders(contactId);
long duration = System.currentTimeMillis() - now;
if(LOG.isLoggable(INFO))
LOG.info("Load took " + duration + " ms");
// Display the headers in the UI
displayHeaders(headers);
displayHeaders(localAuthor, headers);
} catch(NoSuchContactException e) {
if(LOG.isLoggable(INFO)) LOG.info("Contact removed");
finishOnUiThread();
@@ -134,10 +141,11 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
});
}
private void displayHeaders(
private void displayHeaders(final LocalAuthor localAuthor,
final Collection<PrivateMessageHeader> headers) {
runOnUiThread(new Runnable() {
public void run() {
adapter.setLocalAuthorName(localAuthor.getName());
adapter.clear();
for(PrivateMessageHeader h : headers) adapter.add(h);
adapter.sort(AscendingHeaderComparator.INSTANCE);
@@ -205,6 +213,7 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
public void onClick(View view) {
Intent i = new Intent(this, WritePrivateMessageActivity.class);
i.putExtra("net.sf.briar.CONTACT_ID", contactId.getInt());
i.putExtra("net.sf.briar.LOCAL_AUTHOR_ID", localAuthorId.getBytes());
startActivity(i);
}
@@ -218,12 +227,11 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
Intent i = new Intent(this, ReadPrivateMessageActivity.class);
i.putExtra("net.sf.briar.CONTACT_ID", contactId.getInt());
i.putExtra("net.sf.briar.CONTACT_NAME", contactName);
i.putExtra("net.sf.briar.LOCAL_AUTHOR_NAME", localAuthorName);
i.putExtra("net.sf.briar.MESSAGE_ID", item.getId().getBytes());
i.putExtra("net.sf.briar.CONTENT_TYPE", item.getContentType());
i.putExtra("net.sf.briar.TIMESTAMP", item.getTimestamp());
i.putExtra("net.sf.briar.INCOMING", item.isIncoming());
i.putExtra("net.sf.briar.FIRST", position == 0);
i.putExtra("net.sf.briar.LAST", position == adapter.getCount() - 1);
startActivityForResult(i, position);
}
}

View File

@@ -2,14 +2,16 @@ package net.sf.briar.android.messages;
import static android.graphics.Typeface.BOLD;
import static android.widget.LinearLayout.HORIZONTAL;
import static android.widget.LinearLayout.VERTICAL;
import static java.text.DateFormat.SHORT;
import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP_1;
import java.util.ArrayList;
import net.sf.briar.R;
import net.sf.briar.android.widgets.CommonLayoutParams;
import net.sf.briar.android.widgets.HorizontalSpace;
import net.sf.briar.api.db.PrivateMessageHeader;
import net.sf.briar.util.StringUtils;
import android.content.Context;
import android.content.res.Resources;
import android.text.format.DateUtils;
@@ -22,15 +24,26 @@ import android.widget.TextView;
class ConversationAdapter extends ArrayAdapter<PrivateMessageHeader> {
ConversationAdapter(Context ctx) {
private final String contactName;
private String localAuthorName = null;
ConversationAdapter(Context ctx, String contactName) {
super(ctx, android.R.layout.simple_expandable_list_item_1,
new ArrayList<PrivateMessageHeader>());
this.contactName = contactName;
}
void setLocalAuthorName(String localAuthorName) {
this.localAuthorName = localAuthorName;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if(localAuthorName == null) throw new IllegalStateException();
PrivateMessageHeader item = getItem(position);
Context ctx = getContext();
LinearLayout layout = new LinearLayout(ctx);
layout.setOrientation(HORIZONTAL);
if(!item.isRead()) {
@@ -38,23 +51,40 @@ class ConversationAdapter extends ArrayAdapter<PrivateMessageHeader> {
layout.setBackgroundColor(res.getColor(R.color.unread_background));
}
LinearLayout innerLayout = new LinearLayout(ctx);
// Give me all the unused width
innerLayout.setLayoutParams(WRAP_WRAP_1);
innerLayout.setOrientation(VERTICAL);
TextView name = new TextView(ctx);
name.setTextSize(18);
name.setMaxLines(1);
name.setPadding(10, 10, 10, 10);
if(item.isIncoming()) name.setText(contactName);
else name.setText(localAuthorName);
innerLayout.addView(name);
if(item.getContentType().equals("text/plain")) {
TextView subject = new TextView(ctx);
// Give me all the unused width
subject.setLayoutParams(CommonLayoutParams.WRAP_WRAP_1);
subject.setTextSize(14);
subject.setMaxLines(2);
subject.setPadding(10, 10, 10, 10);
if(!item.isRead()) subject.setTypeface(null, BOLD);
subject.setText(item.getSubject());
layout.addView(subject);
if(!StringUtils.isNullOrEmpty(item.getSubject())) {
TextView subject = new TextView(ctx);
subject.setTextSize(14);
subject.setMaxLines(2);
subject.setPadding(10, 0, 10, 10);
if(!item.isRead()) subject.setTypeface(null, BOLD);
subject.setText(item.getSubject());
innerLayout.addView(subject);
}
} else {
LinearLayout attachmentLayout = new LinearLayout(ctx);
attachmentLayout.setOrientation(HORIZONTAL);
ImageView attachment = new ImageView(ctx);
attachment.setPadding(10, 10, 10, 10);
attachment.setPadding(10, 0, 10, 10);
attachment.setImageResource(R.drawable.content_attachment);
layout.addView(attachment);
layout.addView(new HorizontalSpace(ctx));
attachmentLayout.addView(attachment);
attachmentLayout.addView(new HorizontalSpace(ctx));
innerLayout.addView(attachmentLayout);
}
layout.addView(innerLayout);
TextView date = new TextView(ctx);
date.setTextSize(14);

View File

@@ -4,6 +4,8 @@ import static android.view.Gravity.CENTER_HORIZONTAL;
import static android.widget.LinearLayout.VERTICAL;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_MATCH;
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_WRAP_1;
import java.util.ArrayList;
import java.util.Collection;
@@ -16,7 +18,6 @@ import net.sf.briar.R;
import net.sf.briar.android.BriarActivity;
import net.sf.briar.android.BriarService;
import net.sf.briar.android.BriarService.BriarServiceConnection;
import net.sf.briar.android.widgets.CommonLayoutParams;
import net.sf.briar.android.widgets.HorizontalBorder;
import net.sf.briar.api.Contact;
import net.sf.briar.api.ContactId;
@@ -52,7 +53,7 @@ implements OnClickListener, DatabaseListener {
private ConversationListAdapter adapter = null;
private ListView list = null;
// Fields that are accessed from DB threads must be volatile
// Fields that are accessed from background threads must be volatile
@Inject private volatile DatabaseComponent db;
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
@@ -60,14 +61,14 @@ implements OnClickListener, DatabaseListener {
public void onCreate(Bundle state) {
super.onCreate(null);
LinearLayout layout = new LinearLayout(this);
layout.setLayoutParams(CommonLayoutParams.MATCH_MATCH);
layout.setLayoutParams(MATCH_MATCH);
layout.setOrientation(VERTICAL);
layout.setGravity(CENTER_HORIZONTAL);
adapter = new ConversationListAdapter(this);
list = new ListView(this);
// Give me all the width and all the unused height
list.setLayoutParams(CommonLayoutParams.MATCH_WRAP_1);
list.setLayoutParams(MATCH_WRAP_1);
list.setAdapter(adapter);
list.setOnItemClickListener(adapter);
layout.addView(list);
@@ -82,7 +83,7 @@ implements OnClickListener, DatabaseListener {
setContentView(layout);
// Bind to the service so we can wait for the DB to be opened
// Bind to the service so we can wait for it to start
bindService(new Intent(BriarService.class.getName()),
serviceConnection, 0);
}

View File

@@ -5,11 +5,11 @@ import static android.view.Gravity.LEFT;
import static android.widget.LinearLayout.HORIZONTAL;
import static android.widget.LinearLayout.VERTICAL;
import static java.text.DateFormat.SHORT;
import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP_1;
import java.util.ArrayList;
import net.sf.briar.R;
import net.sf.briar.android.widgets.CommonLayoutParams;
import net.sf.briar.util.StringUtils;
import android.content.Context;
import android.content.Intent;
@@ -44,7 +44,7 @@ implements OnItemClickListener {
LinearLayout innerLayout = new LinearLayout(ctx);
// Give me all the unused width
innerLayout.setLayoutParams(CommonLayoutParams.WRAP_WRAP_1);
innerLayout.setLayoutParams(WRAP_WRAP_1);
innerLayout.setOrientation(VERTICAL);
innerLayout.setGravity(LEFT);
@@ -85,6 +85,8 @@ implements OnItemClickListener {
Intent i = new Intent(getContext(), ConversationActivity.class);
i.putExtra("net.sf.briar.CONTACT_ID", item.getContactId().getInt());
i.putExtra("net.sf.briar.CONTACT_NAME", item.getContactName());
i.putExtra("net.sf.briar.LOCAL_AUTHOR_ID",
item.getLocalAuthorId().getBytes());
getContext().startActivity(i);
}
}

View File

@@ -4,6 +4,7 @@ import java.util.Collections;
import java.util.List;
import net.sf.briar.android.DescendingHeaderComparator;
import net.sf.briar.api.AuthorId;
import net.sf.briar.api.Contact;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.db.PrivateMessageHeader;
@@ -34,6 +35,10 @@ class ConversationListItem {
return contact.getAuthor().getName();
}
AuthorId getLocalAuthorId() {
return contact.getLocalAuthorId();
}
String getSubject() {
return subject;
}

View File

@@ -7,6 +7,9 @@ import static android.widget.LinearLayout.VERTICAL;
import static java.text.DateFormat.SHORT;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_WRAP;
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_WRAP_1;
import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP_1;
import java.io.UnsupportedEncodingException;
import java.util.concurrent.Executor;
@@ -16,7 +19,6 @@ import net.sf.briar.R;
import net.sf.briar.android.BriarActivity;
import net.sf.briar.android.BriarService;
import net.sf.briar.android.BriarService.BriarServiceConnection;
import net.sf.briar.android.widgets.CommonLayoutParams;
import net.sf.briar.android.widgets.HorizontalBorder;
import net.sf.briar.android.widgets.HorizontalSpace;
import net.sf.briar.api.ContactId;
@@ -59,7 +61,7 @@ implements OnClickListener {
private ImageButton replyButton = null;
private TextView content = null;
// Fields that are accessed from DB threads must be volatile
// Fields that are accessed from background threads must be volatile
@Inject private volatile DatabaseComponent db;
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
private volatile MessageId messageId = null;
@@ -69,22 +71,20 @@ implements OnClickListener {
super.onCreate(null);
Intent i = getIntent();
int cid = i.getIntExtra("net.sf.briar.CONTACT_ID", -1);
if(cid == -1) throw new IllegalStateException();
contactId = new ContactId(cid);
int id = i.getIntExtra("net.sf.briar.CONTACT_ID", -1);
if(id == -1) throw new IllegalStateException();
contactId = new ContactId(id);
String contactName = i.getStringExtra("net.sf.briar.CONTACT_NAME");
if(contactName == null) throw new IllegalStateException();
setTitle(contactName);
byte[] mid = i.getByteArrayExtra("net.sf.briar.MESSAGE_ID");
if(mid == null) throw new IllegalStateException();
messageId = new MessageId(mid);
byte[] b = i.getByteArrayExtra("net.sf.briar.MESSAGE_ID");
if(b == null) throw new IllegalStateException();
messageId = new MessageId(b);
String contentType = i.getStringExtra("net.sf.briar.CONTENT_TYPE");
if(contentType == null) throw new IllegalStateException();
long timestamp = i.getLongExtra("net.sf.briar.TIMESTAMP", -1);
if(timestamp == -1) throw new IllegalStateException();
boolean incoming = i.getBooleanExtra("net.sf.briar.INCOMING", false);
boolean first = i.getBooleanExtra("net.sf.briar.FIRST", false);
boolean last = i.getBooleanExtra("net.sf.briar.LAST", false);
if(state != null && bundleEncrypter.decrypt(state)) {
read = state.getBoolean("net.sf.briar.READ");
@@ -94,12 +94,12 @@ implements OnClickListener {
}
LinearLayout layout = new LinearLayout(this);
layout.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
layout.setLayoutParams(MATCH_WRAP);
layout.setOrientation(VERTICAL);
ScrollView scrollView = new ScrollView(this);
// Give me all the width and all the unused height
scrollView.setLayoutParams(CommonLayoutParams.MATCH_WRAP_1);
scrollView.setLayoutParams(MATCH_WRAP_1);
LinearLayout message = new LinearLayout(this);
message.setOrientation(VERTICAL);
@@ -107,13 +107,13 @@ implements OnClickListener {
message.setBackgroundColor(res.getColor(R.color.content_background));
LinearLayout header = new LinearLayout(this);
header.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
header.setLayoutParams(MATCH_WRAP);
header.setOrientation(HORIZONTAL);
header.setGravity(CENTER_VERTICAL);
TextView name = new TextView(this);
// Give me all the unused width
name.setLayoutParams(CommonLayoutParams.WRAP_WRAP_1);
name.setLayoutParams(WRAP_WRAP_1);
name.setTextSize(18);
name.setMaxLines(1);
name.setPadding(10, 10, 10, 10);
@@ -144,7 +144,7 @@ implements OnClickListener {
layout.addView(new HorizontalBorder(this));
LinearLayout footer = new LinearLayout(this);
footer.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
footer.setLayoutParams(MATCH_WRAP);
footer.setOrientation(HORIZONTAL);
footer.setGravity(CENTER);
@@ -160,7 +160,6 @@ implements OnClickListener {
prevButton.setBackgroundResource(0);
prevButton.setImageResource(R.drawable.navigation_previous_item);
prevButton.setOnClickListener(this);
prevButton.setEnabled(!first);
footer.addView(prevButton);
footer.addView(new HorizontalSpace(this));
@@ -168,7 +167,6 @@ implements OnClickListener {
nextButton.setBackgroundResource(0);
nextButton.setImageResource(R.drawable.navigation_next_item);
nextButton.setOnClickListener(this);
nextButton.setEnabled(!last);
footer.addView(nextButton);
footer.addView(new HorizontalSpace(this));
@@ -181,7 +179,7 @@ implements OnClickListener {
setContentView(layout);
// Bind to the service so we can wait for the DB to be opened
// Bind to the service so we can wait for it to start
bindService(new Intent(BriarService.class.getName()),
serviceConnection, 0);
}

View File

@@ -5,6 +5,7 @@ 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 static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_WRAP;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
@@ -17,7 +18,6 @@ import net.sf.briar.R;
import net.sf.briar.android.BriarActivity;
import net.sf.briar.android.BriarService;
import net.sf.briar.android.BriarService.BriarServiceConnection;
import net.sf.briar.android.widgets.CommonLayoutParams;
import net.sf.briar.android.widgets.HorizontalSpace;
import net.sf.briar.api.AuthorId;
import net.sf.briar.api.Contact;
@@ -61,7 +61,7 @@ implements OnItemSelectedListener, OnClickListener {
private ImageButton sendButton = null;
private EditText content = null;
// Fields that are accessed from DB threads must be volatile
// Fields that are accessed from background threads must be volatile
@Inject private volatile DatabaseComponent db;
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
@Inject private volatile MessageFactory messageFactory;
@@ -74,17 +74,17 @@ implements OnItemSelectedListener, OnClickListener {
super.onCreate(null);
Intent i = getIntent();
int cid = i.getIntExtra("net.sf.briar.CONTACT_ID", -1);
if(cid != -1) contactId = new ContactId(cid);
byte[] pid = i.getByteArrayExtra("net.sf.briar.PARENT_ID");
if(pid != null) parentId = new MessageId(pid);
int id = i.getIntExtra("net.sf.briar.CONTACT_ID", -1);
if(id != -1) contactId = new ContactId(id);
byte[] b = i.getByteArrayExtra("net.sf.briar.PARENT_ID");
if(b != null) parentId = new MessageId(b);
LinearLayout layout = new LinearLayout(this);
layout.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
layout.setLayoutParams(MATCH_WRAP);
layout.setOrientation(VERTICAL);
LinearLayout header = new LinearLayout(this);
header.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
header.setLayoutParams(MATCH_WRAP);
header.setOrientation(HORIZONTAL);
header.setGravity(CENTER_VERTICAL);
@@ -106,7 +106,7 @@ implements OnItemSelectedListener, OnClickListener {
layout.addView(header);
header = new LinearLayout(this);
header.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
header.setLayoutParams(MATCH_WRAP);
header.setOrientation(HORIZONTAL);
header.setGravity(CENTER_VERTICAL);
@@ -120,7 +120,6 @@ implements OnItemSelectedListener, OnClickListener {
spinner = new Spinner(this);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(this);
loadContactList();
header.addView(spinner);
layout.addView(header);
@@ -134,17 +133,23 @@ implements OnItemSelectedListener, OnClickListener {
setContentView(layout);
// Bind to the service so we can wait for the DB to be opened
// Bind to the service so we can wait for it to start
bindService(new Intent(BriarService.class.getName()),
serviceConnection, 0);
}
private void loadContactList() {
@Override
public void onResume() {
super.onResume();
loadContacts();
}
private void loadContacts() {
dbUiExecutor.execute(new Runnable() {
public void run() {
try {
serviceConnection.waitForStartup();
displayContactList(db.getContacts());
displayContacts(db.getContacts());
} catch(DbException e) {
if(LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
@@ -156,7 +161,7 @@ implements OnItemSelectedListener, OnClickListener {
});
}
private void displayContactList(final Collection<Contact> contacts) {
private void displayContacts(final Collection<Contact> contacts) {
runOnUiThread(new Runnable() {
public void run() {
int index = -1;
@@ -189,11 +194,6 @@ implements OnItemSelectedListener, OnClickListener {
contactId = c.getId();
}
public void onNothingSelected(AdapterView<?> parent) {
contactId = null;
sendButton.setEnabled(false);
}
private void loadLocalAuthor(final AuthorId a) {
dbUiExecutor.execute(new Runnable() {
public void run() {
@@ -215,13 +215,18 @@ implements OnItemSelectedListener, OnClickListener {
}
});
}
public void onNothingSelected(AdapterView<?> parent) {
contactId = null;
sendButton.setEnabled(false);
}
public void onClick(View view) {
if(localAuthor == null || contactId == null)
throw new IllegalStateException();
try {
storeMessage(localAuthor, contactId,
content.getText().toString().getBytes("UTF-8"));
byte[] b = content.getText().toString().getBytes("UTF-8");
storeMessage(localAuthor, contactId, b);
} catch(UnsupportedEncodingException e) {
throw new RuntimeException(e);
}

View File

@@ -3,16 +3,17 @@ package net.sf.briar.android.widgets;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import net.sf.briar.R;
import android.content.Context;
import android.content.res.Resources;
import android.view.View;
import android.widget.LinearLayout.LayoutParams;
public class HorizontalBorder extends View {
private static final int LINE_WIDTH = 5;
public HorizontalBorder(Context ctx) {
super(ctx);
setLayoutParams(new LayoutParams(MATCH_PARENT, LINE_WIDTH));
Resources res = ctx.getResources();
int width = res.getInteger(R.integer.horizontal_border_width);
setLayoutParams(new LayoutParams(MATCH_PARENT, width));
setBackgroundColor(getResources().getColor(R.color.horizontal_border));
}
}