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

@@ -24,6 +24,14 @@
<action android:name="net.sf.briar.android.BriarService" />
</intent-filter>
</service>
<activity
android:name=".android.HomeScreenActivity"
android:label="@string/app_name" >
</activity>
<activity
android:name=".android.SetupActivity"
android:label="@string/app_name" >
</activity>
<activity
android:name=".android.SplashScreenActivity"
android:label="@string/app_name" >
@@ -32,10 +40,6 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".android.HomeScreenActivity"
android:label="@string/app_name" >
</activity>
<activity
android:name=".android.contact.ContactListActivity"
android:label="@string/contact_list_title" >
@@ -56,6 +60,10 @@
android:name=".android.groups.WriteGroupMessageActivity"
android:label="@string/compose_group_title" >
</activity>
<activity
android:name=".android.identity.CreateIdentityActivity"
android:label="@string/create_identity_title" >
</activity>
<activity
android:name=".android.invitation.AddContactActivity"
android:label="@string/add_contact_title" >

View File

@@ -11,4 +11,4 @@
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-16
target=android-17

View File

@@ -1,4 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="LightTheme" parent="android:Theme.Holo.Light" />
<integer name="horizontal_border_width">5</integer>
<integer name="spinner_padding">10</integer>
</resources>

View File

@@ -49,4 +49,8 @@
<string name="groups_title">Groups</string>
<string name="compose_group_title">New Post</string>
<string name="blogs_title">Blogs</string>
<string name="create_identity_item">New identity\u2026</string>
<string name="create_identity_title">Create an Identity</string>
<string name="choose_nickname">Choose your nickname:</string>
<string name="create_button">Create</string>
</resources>

View File

@@ -1,4 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="LightTheme" parent="android:Theme.Light" />
<integer name="horizontal_border_width">2</integer>
<integer name="spinner_padding">0</integer>
</resources>

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));
}
}

View File

@@ -37,12 +37,8 @@ import net.sf.briar.api.transport.TemporarySecret;
*/
public interface DatabaseComponent {
/**
* Opens the database.
* @param resume true to reopen an existing database or false to create a
* new one.
*/
void open(boolean resume) throws DbException, IOException;
/** Opens the database and returns true if the database already existed. */
boolean open() throws DbException, IOException;
/** Waits for any open transactions to finish and closes the database. */
void close() throws DbException, IOException;

View File

@@ -4,7 +4,9 @@ import java.io.File;
public interface DatabaseConfig {
File getDataDirectory();
boolean databaseExists();
File getDatabaseDirectory();
char[] getPassword();

View File

@@ -54,12 +54,8 @@ import net.sf.briar.api.transport.TemporarySecret;
*/
interface Database<T> {
/**
* Opens the database.
* @param resume true to reopen an existing database, false to create a
* new one.
*/
void open(boolean resume) throws DbException, IOException;
/** Opens the database and returns true if the database already existed. */
boolean open() throws DbException, IOException;
/**
* Prevents new transactions from starting, waits for all current

View File

@@ -140,11 +140,11 @@ DatabaseCleaner.Callback {
this.clock = clock;
}
public void open(boolean resume) throws DbException, IOException {
public boolean open() throws DbException, IOException {
synchronized(openCloseLock) {
if(open) throw new IllegalStateException();
open = true;
db.open(resume);
boolean reopened = db.open();
cleaner.startCleaning(this, MS_BETWEEN_SWEEPS);
shutdownHandle = shutdown.addShutdownHook(new Runnable() {
public void run() {
@@ -162,6 +162,7 @@ DatabaseCleaner.Callback {
}
}
});
return reopened;
}
}

View File

@@ -23,23 +23,23 @@ class H2Database extends JdbcDatabase {
private static final String COUNTER_TYPE = "INT NOT NULL AUTO_INCREMENT";
private static final String SECRET_TYPE = "BINARY(32)";
private final File home;
private final File dir;
private final String url;
private final char[] password;
private final long maxSize;
@Inject
H2Database(DatabaseConfig config, Clock clock) {
super(HASH_TYPE, BINARY_TYPE, COUNTER_TYPE, SECRET_TYPE, clock);
home = new File(config.getDataDirectory(), "db");
url = "jdbc:h2:split:" + home.getPath()
super(HASH_TYPE, BINARY_TYPE, COUNTER_TYPE, SECRET_TYPE, config, clock);
dir = config.getDatabaseDirectory();
url = "jdbc:h2:split:" + new File(dir, "db").getPath()
+ ";CIPHER=AES;MULTI_THREADED=1;DB_CLOSE_ON_EXIT=false";
password = config.getPassword();
maxSize = config.getMaxSize();
}
public void open(boolean resume) throws DbException, IOException {
super.open(resume, home.getParentFile(), "org.h2.Driver");
public boolean open() throws DbException, IOException {
return super.open("org.h2.Driver");
}
public void close() throws DbException {
@@ -53,7 +53,6 @@ class H2Database extends JdbcDatabase {
public long getFreeSpace() throws DbException {
try {
File dir = home.getParentFile();
long free = FileUtils.getFreeSpace(dir);
long used = getDiskSpace(dir);
long quota = maxSize - used;

View File

@@ -10,7 +10,6 @@ import static net.sf.briar.api.messaging.Rating.UNRATED;
import static net.sf.briar.db.ExponentialBackoff.calculateExpiry;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
@@ -36,6 +35,7 @@ import net.sf.briar.api.TransportConfig;
import net.sf.briar.api.TransportId;
import net.sf.briar.api.TransportProperties;
import net.sf.briar.api.clock.Clock;
import net.sf.briar.api.db.DatabaseConfig;
import net.sf.briar.api.db.DbClosedException;
import net.sf.briar.api.db.DbException;
import net.sf.briar.api.db.GroupMessageHeader;
@@ -54,7 +54,6 @@ import net.sf.briar.api.messaging.TransportAck;
import net.sf.briar.api.messaging.TransportUpdate;
import net.sf.briar.api.transport.Endpoint;
import net.sf.briar.api.transport.TemporarySecret;
import net.sf.briar.util.FileUtils;
/**
* A generic database implementation that can be used with any JDBC-compatible
@@ -360,6 +359,7 @@ abstract class JdbcDatabase implements Database<Connection> {
// Different database libraries use different names for certain types
private final String hashType, binaryType, counterType, secretType;
private final DatabaseConfig config;
private final Clock clock;
private final LinkedList<Connection> connections =
@@ -371,38 +371,39 @@ abstract class JdbcDatabase implements Database<Connection> {
protected abstract Connection createConnection() throws SQLException;
JdbcDatabase(String hashType, String binaryType, String counterType,
String secretType, Clock clock) {
String secretType, DatabaseConfig config, Clock clock) {
this.hashType = hashType;
this.binaryType = binaryType;
this.counterType = counterType;
this.secretType = secretType;
this.config = config;
this.clock = clock;
}
protected void open(boolean resume, File dir, String driverClass)
throws DbException, IOException {
if(resume) {
if(!dir.exists()) throw new FileNotFoundException();
if(!dir.isDirectory()) throw new FileNotFoundException();
} else {
if(dir.exists()) FileUtils.delete(dir);
protected boolean open(String driverClass) throws DbException, IOException {
boolean reopen = config.databaseExists();
File dir = config.getDatabaseDirectory();
if(LOG.isLoggable(INFO)) {
LOG.info("Database directory: " + dir.getPath());
if(reopen) for(File f : dir.listFiles()) LOG.info(f.getPath());
}
if(!reopen) dir.mkdirs();
// Load the JDBC driver
try {
Class.forName(driverClass);
} catch(ClassNotFoundException e) {
throw new DbException(e);
}
// Open the database
// Open the database and create the tables if necessary
Connection txn = startTransaction();
try {
// If not resuming, create the tables
if(!resume) createTables(txn);
if(!reopen) createTables(txn);
commitTransaction(txn);
} catch(DbException e) {
abortTransaction(txn);
throw e;
}
return reopen;
}
private void createTables(Connection txn) throws DbException {
@@ -1246,11 +1247,12 @@ abstract class JdbcDatabase implements Database<Connection> {
rs = ps.executeQuery();
List<Endpoint> endpoints = new ArrayList<Endpoint>();
while(rs.next()) {
ContactId c = new ContactId(rs.getInt(1));
TransportId t = new TransportId(rs.getBytes(2));
ContactId contactId = new ContactId(rs.getInt(1));
TransportId transportId = new TransportId(rs.getBytes(2));
long epoch = rs.getLong(3);
boolean alice = rs.getBoolean(4);
endpoints.add(new Endpoint(c, t, epoch, alice));
endpoints.add(new Endpoint(contactId, transportId, epoch,
alice));
}
return Collections.unmodifiableList(endpoints);
} catch(SQLException e) {
@@ -1367,9 +1369,12 @@ abstract class JdbcDatabase implements Database<Connection> {
rs = ps.executeQuery();
List<LocalAuthor> authors = new ArrayList<LocalAuthor>();
while(rs.next()) {
AuthorId id = new AuthorId(rs.getBytes(1));
authors.add(new LocalAuthor(id, rs.getString(2), rs.getBytes(3),
rs.getBytes(4)));
AuthorId authorId = new AuthorId(rs.getBytes(1));
String name = rs.getString(2);
byte[] publicKey = rs.getBytes(3);
byte[] privateKey = rs.getBytes(4);
authors.add(new LocalAuthor(authorId, name, publicKey,
privateKey));
}
rs.close();
ps.close();
@@ -1392,9 +1397,12 @@ abstract class JdbcDatabase implements Database<Connection> {
rs = ps.executeQuery();
List<LocalGroup> groups = new ArrayList<LocalGroup>();
while(rs.next()) {
GroupId id = new GroupId(rs.getBytes(1));
groups.add(new LocalGroup(id, rs.getString(2), rs.getBytes(3),
rs.getBytes(4)));
GroupId groupId = new GroupId(rs.getBytes(1));
String name = rs.getString(2);
byte[] publicKey = rs.getBytes(3);
byte[] privateKey = rs.getBytes(4);
groups.add(new LocalGroup(groupId, name, publicKey,
privateKey));
}
rs.close();
ps.close();
@@ -2048,8 +2056,8 @@ abstract class JdbcDatabase implements Database<Connection> {
rs = ps.executeQuery();
List<TemporarySecret> secrets = new ArrayList<TemporarySecret>();
while(rs.next()) {
ContactId c = new ContactId(rs.getInt(1));
TransportId t = new TransportId(rs.getBytes(2));
ContactId contactId = new ContactId(rs.getInt(1));
TransportId transportId = new TransportId(rs.getBytes(2));
long epoch = rs.getLong(3);
boolean alice = rs.getBoolean(4);
long period = rs.getLong(5);
@@ -2057,8 +2065,8 @@ abstract class JdbcDatabase implements Database<Connection> {
long outgoing = rs.getLong(7);
long centre = rs.getLong(8);
byte[] bitmap = rs.getBytes(9);
secrets.add(new TemporarySecret(c, t, epoch, alice, period,
secret, outgoing, centre, bitmap));
secrets.add(new TemporarySecret(contactId, transportId, epoch,
alice, period, secret, outgoing, centre, bitmap));
}
rs.close();
ps.close();
@@ -2186,10 +2194,10 @@ abstract class JdbcDatabase implements Database<Connection> {
rs = ps.executeQuery();
List<Group> subs = new ArrayList<Group>();
while(rs.next()) {
GroupId id = new GroupId(rs.getBytes(1));
GroupId groupId = new GroupId(rs.getBytes(1));
String name = rs.getString(2);
byte[] publicKey = rs.getBytes(3);
subs.add(new Group(id, name, publicKey));
subs.add(new Group(groupId, name, publicKey));
}
rs.close();
ps.close();
@@ -2213,10 +2221,10 @@ abstract class JdbcDatabase implements Database<Connection> {
rs = ps.executeQuery();
List<Group> subs = new ArrayList<Group>();
while(rs.next()) {
GroupId id = new GroupId(rs.getBytes(1));
GroupId groupId = new GroupId(rs.getBytes(1));
String name = rs.getString(2);
byte[] publicKey = rs.getBytes(3);
subs.add(new Group(id, name, publicKey));
subs.add(new Group(groupId, name, publicKey));
}
rs.close();
ps.close();
@@ -2286,10 +2294,10 @@ abstract class JdbcDatabase implements Database<Connection> {
long version = 0;
int txCount = 0;
while(rs.next()) {
byte[] id = rs.getBytes(1);
GroupId groupId = new GroupId(rs.getBytes(1));
String name = rs.getString(2);
byte[] key = rs.getBytes(3);
subs.add(new Group(new GroupId(id), name, key));
subs.add(new Group(groupId, name, key));
version = rs.getLong(4);
txCount = rs.getInt(5);
}
@@ -2483,8 +2491,8 @@ abstract class JdbcDatabase implements Database<Connection> {
rs = ps.executeQuery();
Map<GroupId, Integer> counts = new HashMap<GroupId, Integer>();
while(rs.next()) {
GroupId g = new GroupId(rs.getBytes(1));
counts.put(g, rs.getInt(2));
GroupId groupId = new GroupId(rs.getBytes(1));
counts.put(groupId, rs.getInt(2));
}
rs.close();
ps.close();

View File

@@ -14,7 +14,11 @@ public class TestDatabaseConfig implements DatabaseConfig {
this.maxSize = maxSize;
}
public File getDataDirectory() {
public boolean databaseExists() {
return dir.isDirectory() && dir.listFiles().length > 0;
}
public File getDatabaseDirectory() {
return dir;
}

View File

@@ -125,8 +125,9 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
exactly(13).of(database).startTransaction();
will(returnValue(txn));
exactly(13).of(database).commitTransaction(txn);
// open(false)
oneOf(database).open(false);
// open()
oneOf(database).open();
will(returnValue(false));
oneOf(cleaner).startCleaning(
with(any(DatabaseCleaner.Callback.class)),
with(any(long.class)));
@@ -199,7 +200,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
DatabaseComponent db = createDatabaseComponent(database, cleaner,
shutdown);
db.open(false);
assertFalse(db.open());
db.addListener(listener);
assertEquals(UNRATED, db.getRating(authorId));
db.setRating(authorId, GOOD); // First time - listeners called

View File

@@ -1832,7 +1832,8 @@ public class H2DatabaseTest extends BriarTestCase {
private Database<Connection> open(boolean resume) throws Exception {
Database<Connection> db = new H2Database(new TestDatabaseConfig(testDir,
MAX_SIZE), new SystemClock());
db.open(resume);
if(!resume) TestUtils.deleteTestDirectory(testDir);
db.open();
return db;
}

View File

@@ -102,7 +102,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
private byte[] write() throws Exception {
// Open Alice's database
DatabaseComponent db = alice.getInstance(DatabaseComponent.class);
db.open(false);
assertFalse(db.open());
// Start Alice's key manager
KeyManager km = alice.getInstance(KeyManager.class);
km.start();
@@ -156,7 +156,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
private void read(byte[] b) throws Exception {
// Open Bob's database
DatabaseComponent db = bob.getInstance(DatabaseComponent.class);
db.open(false);
assertFalse(db.open());
// Start Bob's key manager
KeyManager km = bob.getInstance(KeyManager.class);
km.start();