Separated Android code and core code into distinct Eclipse projects.

This should make it possible to develop the core in Eclipse without the ADT.
This commit is contained in:
akwizgran
2012-12-05 20:39:31 +00:00
parent 366d391d89
commit f4f7b96d50
345 changed files with 43 additions and 19 deletions

View File

@@ -0,0 +1,82 @@
package net.sf.briar.android;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicBoolean;
import net.sf.briar.api.android.AndroidExecutor;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import com.google.inject.Inject;
class AndroidExecutorImpl implements AndroidExecutor {
private static final int SHUTDOWN = 0, RUN = 1;
private final Runnable loop;
private final AtomicBoolean started = new AtomicBoolean(false);
private final CountDownLatch startLatch = new CountDownLatch(1);
private volatile Handler handler = null;
@Inject
AndroidExecutorImpl() {
loop = new Runnable() {
public void run() {
Looper.prepare();
handler = new FutureTaskHandler();
startLatch.countDown();
Looper.loop();
}
};
}
private void startIfNecessary() {
if(started.getAndSet(true)) return;
new Thread(loop, "AndroidExecutor").start();
try {
startLatch.await();
} catch(InterruptedException e) {
Thread.currentThread().interrupt();
}
}
public <V> V run(Callable<V> c) throws InterruptedException,
ExecutionException {
startIfNecessary();
Future<V> f = new FutureTask<V>(c);
Message m = Message.obtain(handler, RUN, f);
handler.sendMessage(m);
return f.get();
}
public void shutdown() {
if(handler != null) {
Message m = Message.obtain(handler, SHUTDOWN);
handler.sendMessage(m);
}
}
private static class FutureTaskHandler extends Handler {
@Override
public void handleMessage(Message m) {
switch(m.what) {
case SHUTDOWN:
Looper.myLooper().quit();
break;
case RUN:
((FutureTask<?>) m.obj).run();
break;
default:
throw new IllegalArgumentException();
}
}
}
}

View File

@@ -0,0 +1,13 @@
package net.sf.briar.android;
import net.sf.briar.api.android.AndroidExecutor;
import com.google.inject.AbstractModule;
public class AndroidModule extends AbstractModule {
@Override
protected void configure() {
bind(AndroidExecutor.class).to(AndroidExecutorImpl.class);
}
}

View File

@@ -0,0 +1,71 @@
package net.sf.briar.android.helloworld;
import static android.view.Gravity.CENTER_HORIZONTAL;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.widget.LinearLayout.VERTICAL;
import static java.util.logging.Level.INFO;
import java.util.logging.Logger;
import net.sf.briar.R;
import net.sf.briar.android.invitation.AddContactActivity;
import roboguice.activity.RoboActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.TextView;
public class HelloWorldActivity extends RoboActivity
implements OnClickListener {
private static final Logger LOG =
Logger.getLogger(HelloWorldActivity.class.getName());
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(LOG.isLoggable(INFO)) LOG.info("Created");
LinearLayout layout = new LinearLayout(this);
layout.setLayoutParams(new LayoutParams(MATCH_PARENT, MATCH_PARENT));
layout.setOrientation(VERTICAL);
layout.setGravity(CENTER_HORIZONTAL);
TextView welcome = new TextView(this);
welcome.setPadding(0, 0, 0, 10);
welcome.setText(R.string.welcome);
layout.addView(welcome);
TextView faceToFace = new TextView(this);
faceToFace.setPadding(0, 0, 0, 10);
faceToFace.setText(R.string.face_to_face);
layout.addView(faceToFace);
Button addContact = new Button(this);
LayoutParams lp = new LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
addContact.setLayoutParams(lp);
addContact.setText(R.string.add_contact_button);
addContact.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.social_add_person, 0, 0, 0);
addContact.setOnClickListener(this);
layout.addView(addContact);
setContentView(layout);
startService(new Intent(HelloWorldService.class.getName()));
}
@Override
public void onDestroy() {
super.onDestroy();
if(LOG.isLoggable(INFO)) LOG.info("Destroyed");
}
public void onClick(View view) {
startActivity(new Intent(this, AddContactActivity.class));
}
}

View File

@@ -0,0 +1,56 @@
package net.sf.briar.android.helloworld;
import static android.content.Context.MODE_PRIVATE;
import java.io.File;
import net.sf.briar.api.crypto.Password;
import net.sf.briar.api.db.DatabaseConfig;
import net.sf.briar.api.ui.UiCallback;
import android.app.Application;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.Singleton;
public class HelloWorldModule extends AbstractModule {
@Override
protected void configure() {
bind(UiCallback.class).toInstance(new UiCallback() {
public int showChoice(String[] options, String... message) {
return -1;
}
public boolean showConfirmationMessage(String... message) {
return false;
}
public void showMessage(String... message) {}
});
}
@Provides @Singleton
DatabaseConfig getDatabaseConfig(final Application app) {
return new DatabaseConfig() {
public File getDataDirectory() {
return app.getApplicationContext().getDir("db", MODE_PRIVATE);
}
public Password getPassword() {
return new Password() {
public char[] getPassword() {
return "foo bar".toCharArray();
}
};
}
public long getMaxSize() {
return Long.MAX_VALUE;
}
};
}
}

View File

@@ -0,0 +1,97 @@
package net.sf.briar.android.helloworld;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import java.io.IOException;
import java.util.logging.Logger;
import net.sf.briar.api.crypto.KeyManager;
import net.sf.briar.api.db.DatabaseComponent;
import net.sf.briar.api.db.DbException;
import net.sf.briar.api.plugins.PluginManager;
import roboguice.service.RoboService;
import android.content.Intent;
import android.os.IBinder;
import com.google.inject.Inject;
public class HelloWorldService extends RoboService {
private static final Logger LOG =
Logger.getLogger(HelloWorldService.class.getName());
@Inject private DatabaseComponent db;
@Inject private KeyManager keyManager;
@Inject private PluginManager pluginManager;
@Override
public void onCreate() {
super.onCreate();
if(LOG.isLoggable(INFO)) LOG.info("Created");
new Thread() {
@Override
public void run() {
startServices();
}
}.start();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(LOG.isLoggable(INFO)) LOG.info("Started");
return 0;
}
@Override
public IBinder onBind(Intent intent) {
if(LOG.isLoggable(INFO)) LOG.info("Bound");
return null;
}
@Override
public void onDestroy() {
super.onDestroy();
if(LOG.isLoggable(INFO)) LOG.info("Destroyed");
new Thread() {
@Override
public void run() {
stopServices();
}
}.start();
}
private void startServices() {
try {
if(LOG.isLoggable(INFO)) LOG.info("Starting");
db.open(false);
if(LOG.isLoggable(INFO)) LOG.info("Database opened");
keyManager.start();
if(LOG.isLoggable(INFO)) LOG.info("Key manager started");
int pluginsStarted = pluginManager.start(this);
if(LOG.isLoggable(INFO))
LOG.info(pluginsStarted + " plugins started");
} catch(DbException e) {
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
} catch(IOException e) {
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
}
}
private void stopServices() {
try {
if(LOG.isLoggable(INFO)) LOG.info("Shutting down");
int pluginsStopped = pluginManager.stop();
if(LOG.isLoggable(INFO))
LOG.info(pluginsStopped + " plugins stopped");
keyManager.stop();
if(LOG.isLoggable(INFO)) LOG.info("Key manager stopped");
db.close();
if(LOG.isLoggable(INFO)) LOG.info("Database closed");
} catch(DbException e) {
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
} catch(IOException e) {
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
}
}
}

View File

@@ -0,0 +1,225 @@
package net.sf.briar.android.invitation;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.invitation.InvitationListener;
import net.sf.briar.api.invitation.InvitationManager;
import net.sf.briar.api.invitation.InvitationState;
import net.sf.briar.api.invitation.InvitationTask;
import roboguice.activity.RoboActivity;
import android.os.Bundle;
import com.google.inject.Inject;
public class AddContactActivity extends RoboActivity
implements InvitationListener {
@Inject private CryptoComponent crypto;
@Inject private InvitationManager invitationManager;
// All of the following must be accessed on the UI thread
private AddContactView view = null;
private InvitationTask task = null;
private String networkName = null;
private boolean useBluetooth = false;
private int localInvitationCode = -1, remoteInvitationCode = -1;
private int localConfirmationCode = -1, remoteConfirmationCode = -1;
private boolean connectionFailed = false;
private boolean localCompared = false, remoteCompared = false;
private boolean localMatched = false, remoteMatched = false;
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
if(state == null) {
// This is a new activity
setView(new NetworkSetupView(this));
} else {
// Restore the activity's state
networkName = state.getString("net.sf.briar.NETWORK_NAME");
useBluetooth = state.getBoolean("net.sf.briar.USE_BLUETOOTH");
int handle = state.getInt("TASK_HANDLE", -1);
task = invitationManager.getTask(handle);
if(task == null) {
// No background task - we must be in an initial or final state
localInvitationCode = state.getInt("net.sf.briar.LOCAL_CODE");
remoteInvitationCode = state.getInt("net.sf.briar.REMOTE_CODE");
connectionFailed = state.getBoolean("net.sf.briar.FAILED");
if(state.getBoolean("net.sf.briar.MATCHED")) {
localCompared = remoteCompared = true;
localMatched = remoteMatched = true;
}
// Set the appropriate view for the state
if(localInvitationCode == -1) {
setView(new NetworkSetupView(this));
} else if(remoteInvitationCode == -1) {
setView(new InvitationCodeView(this));
} else if(connectionFailed) {
setView(new ConnectionFailedView(this));
} else if(localMatched && remoteMatched) {
setView(new ContactAddedView(this));
} else {
setView(new CodesDoNotMatchView(this));
}
} else {
// A background task exists - listen to it and get its state
InvitationState s = task.addListener(this);
localInvitationCode = s.getLocalInvitationCode();
remoteInvitationCode = s.getRemoteInvitationCode();
localConfirmationCode = s.getLocalConfirmationCode();
remoteConfirmationCode = s.getRemoteConfirmationCode();
connectionFailed = s.getConnectionFailed();
localCompared = s.getLocalCompared();
remoteCompared = s.getRemoteCompared();
localMatched = s.getLocalMatched();
remoteMatched = s.getRemoteMatched();
// Set the appropriate view for the state
if(localInvitationCode == -1) {
setView(new NetworkSetupView(this));
} else if(remoteInvitationCode == -1) {
setView(new InvitationCodeView(this));
} else if(localConfirmationCode == -1) {
setView(new ConnectionView(this));
} else if(connectionFailed) {
setView(new ConnectionFailedView(this));
} else if(!localCompared) {
setView(new ConfirmationCodeView(this));
} else if(!remoteCompared) {
setView(new WaitForContactView(this));
} else if(localMatched && remoteMatched) {
setView(new ContactAddedView(this));
} else {
setView(new CodesDoNotMatchView(this));
}
}
}
}
@Override
public void onResume() {
super.onResume();
view.populate();
}
@Override
public void onSaveInstanceState(Bundle state) {
super.onSaveInstanceState(state);
state.putString("net.sf.briar.NETWORK_NAME", networkName);
state.putBoolean("net.sf.briar.USE_BLUETOOTH", useBluetooth);
state.putInt("net.sf.briar.LOCAL_CODE", localInvitationCode);
state.putInt("net.sf.briar.REMOTE_CODE", remoteInvitationCode);
state.putBoolean("net.sf.briar.FAILED", connectionFailed);
state.putBoolean("net.sf.briar.MATCHED", localMatched && remoteMatched);
if(task != null) state.putInt("TASK_HANDLE", task.getHandle());
}
@Override
public void onDestroy() {
super.onDestroy();
if(task != null) task.removeListener(this);
}
void setView(AddContactView view) {
this.view = view;
view.init(this);
setContentView(view);
}
void reset(AddContactView view) {
task = null;
networkName = null;
useBluetooth = false;
localInvitationCode = -1;
localConfirmationCode = remoteConfirmationCode = -1;
connectionFailed = false;
localCompared = remoteCompared = false;
localMatched = remoteMatched = false;
setView(view);
}
void setNetworkName(String networkName) {
this.networkName = networkName;
}
String getNetworkName() {
return networkName;
}
void setUseBluetooth(boolean useBluetooth) {
this.useBluetooth = useBluetooth;
}
boolean getUseBluetooth() {
return useBluetooth;
}
int getLocalInvitationCode() {
if(localInvitationCode == -1)
localInvitationCode = crypto.generateInvitationCode();
return localInvitationCode;
}
void remoteInvitationCodeEntered(int code) {
setView(new ConnectionView(this));
// FIXME: These calls are blocking the UI thread for too long
task = invitationManager.createTask(localInvitationCode, code);
task.addListener(AddContactActivity.this);
task.connect();
}
int getLocalConfirmationCode() {
return localConfirmationCode;
}
void remoteConfirmationCodeEntered(int code) {
if(code == remoteConfirmationCode) {
localMatched = true;
if(remoteMatched) setView(new ContactAddedView(this));
else if(remoteCompared) setView(new CodesDoNotMatchView(this));
else setView(new WaitForContactView(this));
task.localConfirmationSucceeded();
} else {
setView(new CodesDoNotMatchView(this));
task.localConfirmationFailed();
}
}
public void connectionSucceeded(final int localCode, final int remoteCode) {
runOnUiThread(new Runnable() {
public void run() {
localConfirmationCode = localCode;
remoteConfirmationCode = remoteCode;
setView(new ConfirmationCodeView(AddContactActivity.this));
}
});
}
public void connectionFailed() {
runOnUiThread(new Runnable() {
public void run() {
connectionFailed = true;
setView(new ConnectionFailedView(AddContactActivity.this));
}
});
}
public void remoteConfirmationSucceeded() {
runOnUiThread(new Runnable() {
public void run() {
remoteCompared = true;
remoteMatched = true;
if(localMatched)
setView(new ContactAddedView(AddContactActivity.this));
}
});
}
public void remoteConfirmationFailed() {
runOnUiThread(new Runnable() {
public void run() {
remoteCompared = true;
if(localMatched)
setView(new CodesDoNotMatchView(AddContactActivity.this));
}
});
}
}

View File

@@ -0,0 +1,25 @@
package net.sf.briar.android.invitation;
import static android.view.Gravity.CENTER_HORIZONTAL;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import android.content.Context;
import android.widget.LinearLayout;
abstract class AddContactView extends LinearLayout {
protected AddContactActivity container = null;
AddContactView(Context context) {
super(context);
}
void init(AddContactActivity container) {
this.container = container;
setLayoutParams(new LayoutParams(MATCH_PARENT, MATCH_PARENT));
setOrientation(VERTICAL);
setGravity(CENTER_HORIZONTAL);
populate();
}
abstract void populate();
}

View File

@@ -0,0 +1,6 @@
package net.sf.briar.android.invitation;
interface BluetoothStateListener {
void bluetoothStateChanged(boolean enabled);
}

View File

@@ -0,0 +1,93 @@
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 android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import net.sf.briar.R;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.Intent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class BluetoothWidget extends LinearLayout implements OnClickListener {
private BluetoothStateListener listener = null;
public BluetoothWidget(Context ctx) {
super(ctx);
}
void init(BluetoothStateListener listener) {
this.listener = listener;
setOrientation(HORIZONTAL);
setGravity(CENTER);
populate();
}
void populate() {
removeAllViews();
Context ctx = getContext();
TextView status = new TextView(ctx);
status.setLayoutParams(new LayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1));
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if(adapter == null) {
bluetoothStateChanged(false);
ImageView warning = new ImageView(ctx);
warning.setImageResource(R.drawable.alerts_and_states_warning);
warning.setPadding(10, 10, 10, 10);
addView(warning);
status.setText(R.string.bluetooth_not_available);
addView(status);
} else if(adapter.getScanMode() == SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
bluetoothStateChanged(true);
ImageView ok = new ImageView(ctx);
ok.setImageResource(R.drawable.navigation_accept);
ok.setPadding(10, 10, 10, 10);
addView(ok);
status.setText(R.string.bluetooth_enabled);
addView(status);
ImageButton settings = new ImageButton(ctx);
settings.setImageResource(R.drawable.action_settings);
settings.setOnClickListener(this);
addView(settings);
} else if(adapter.isEnabled()) {
bluetoothStateChanged(false);
ImageView warning = new ImageView(ctx);
warning.setImageResource(R.drawable.alerts_and_states_warning);
warning.setPadding(10, 10, 10, 10);
addView(warning);
status.setText(R.string.bluetooth_not_discoverable);
addView(status);
ImageButton settings = new ImageButton(ctx);
settings.setImageResource(R.drawable.action_settings);
settings.setOnClickListener(this);
addView(settings);
} else {
bluetoothStateChanged(false);
ImageView warning = new ImageView(ctx);
warning.setImageResource(R.drawable.alerts_and_states_warning);
warning.setPadding(10, 10, 10, 10);
addView(warning);
status.setText(R.string.bluetooth_disabled);
addView(status);
ImageButton settings = new ImageButton(ctx);
settings.setImageResource(R.drawable.action_settings);
settings.setOnClickListener(this);
addView(settings);
}
}
private void bluetoothStateChanged(boolean enabled) {
listener.bluetoothStateChanged(enabled);
}
public void onClick(View view) {
getContext().startActivity(new Intent(ACTION_BLUETOOTH_SETTINGS));
}
}

View File

@@ -0,0 +1,6 @@
package net.sf.briar.android.invitation;
interface CodeEntryListener {
void codeEntered(int remoteCode);
}

View File

@@ -0,0 +1,93 @@
package net.sf.briar.android.invitation;
import static android.content.Context.INPUT_METHOD_SERVICE;
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.api.plugins.InvitationConstants.MAX_CODE;
import net.sf.briar.R;
import android.content.Context;
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.TextView;
import android.widget.TextView.OnEditorActionListener;
public class CodeEntryWidget extends LinearLayout implements
OnEditorActionListener, OnClickListener {
private CodeEntryListener listener = null;
private EditText codeEntry = null;
public CodeEntryWidget(Context ctx) {
super(ctx);
}
void init(CodeEntryListener listener, String prompt) {
this.listener = listener;
setOrientation(VERTICAL);
setGravity(CENTER_HORIZONTAL);
Context ctx = getContext();
TextView enterCode = new TextView(ctx);
enterCode.setGravity(CENTER_HORIZONTAL);
enterCode.setPadding(0, 0, 0, 10);
enterCode.setText(prompt);
addView(enterCode);
final Button continueButton = new Button(ctx);
continueButton.setText(R.string.continue_button);
continueButton.setEnabled(false);
continueButton.setOnClickListener(this);
codeEntry = new EditText(ctx) {
@Override
protected void onTextChanged(CharSequence text, int start,
int lengthBefore, int lengthAfter) {
continueButton.setEnabled(text.length() == 6);
}
};
codeEntry.setOnEditorActionListener(this);
codeEntry.setMinEms(5);
codeEntry.setMaxEms(5);
codeEntry.setMaxLines(1);
codeEntry.setInputType(TYPE_CLASS_NUMBER);
LinearLayout innerLayout = new LinearLayout(ctx);
innerLayout.setOrientation(HORIZONTAL);
innerLayout.setGravity(CENTER);
innerLayout.addView(codeEntry);
innerLayout.addView(continueButton);
addView(innerLayout);
}
public boolean onEditorAction(TextView textView, int actionId, KeyEvent e) {
if(!validateAndReturnCode()) codeEntry.setText("");
return true;
}
public void onClick(View view) {
if(!validateAndReturnCode()) codeEntry.setText("");
}
private boolean validateAndReturnCode() {
String remoteCodeString = codeEntry.getText().toString();
int remoteCode;
try {
remoteCode = Integer.valueOf(remoteCodeString);
} catch(NumberFormatException e) {
return false;
}
if(remoteCode < 0 || remoteCode > MAX_CODE) return false;
// Hide the soft keyboard
Object o = getContext().getSystemService(INPUT_METHOD_SERVICE);
((InputMethodManager) o).toggleSoftInput(HIDE_IMPLICIT_ONLY, 0);
listener.codeEntered(remoteCode);
return true;
}
}

View File

@@ -0,0 +1,58 @@
package net.sf.briar.android.invitation;
import static android.view.Gravity.CENTER;
import static android.view.Gravity.CENTER_HORIZONTAL;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import net.sf.briar.R;
import android.content.Context;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class CodesDoNotMatchView extends AddContactView
implements OnClickListener {
CodesDoNotMatchView(Context ctx) {
super(ctx);
}
void populate() {
removeAllViews();
Context ctx = getContext();
LinearLayout innerLayout = new LinearLayout(ctx);
innerLayout.setOrientation(HORIZONTAL);
innerLayout.setGravity(CENTER);
ImageView icon = new ImageView(ctx);
icon.setPadding(10, 10, 10, 10);
icon.setImageResource(R.drawable.alerts_and_states_error);
innerLayout.addView(icon);
TextView failed = new TextView(ctx);
failed.setTextSize(20);
failed.setText(R.string.codes_do_not_match);
innerLayout.addView(failed);
addView(innerLayout);
TextView interfering = new TextView(ctx);
interfering.setGravity(CENTER_HORIZONTAL);
interfering.setPadding(0, 0, 0, 10);
interfering.setText(R.string.interfering);
addView(interfering);
Button tryAgain = new Button(ctx);
LayoutParams lp = new LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
tryAgain.setLayoutParams(lp);
tryAgain.setText(R.string.try_again_button);
tryAgain.setOnClickListener(this);
addView(tryAgain);
}
public void onClick(View view) {
// Try again
container.reset(new NetworkSetupView(container));
}
}

View File

@@ -0,0 +1,58 @@
package net.sf.briar.android.invitation;
import static android.view.Gravity.CENTER;
import static android.view.Gravity.CENTER_HORIZONTAL;
import net.sf.briar.R;
import android.content.Context;
import android.content.res.Resources;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class ConfirmationCodeView extends AddContactView
implements CodeEntryListener {
ConfirmationCodeView(Context ctx) {
super(ctx);
}
void populate() {
removeAllViews();
Context ctx = getContext();
LinearLayout innerLayout = new LinearLayout(ctx);
innerLayout.setOrientation(HORIZONTAL);
innerLayout.setGravity(CENTER);
ImageView icon = new ImageView(ctx);
icon.setPadding(10, 10, 10, 10);
icon.setImageResource(R.drawable.navigation_accept);
innerLayout.addView(icon);
TextView connected = new TextView(ctx);
connected.setTextSize(20);
connected.setText(R.string.connected_to_contact);
innerLayout.addView(connected);
addView(innerLayout);
TextView yourCode = new TextView(ctx);
yourCode.setGravity(CENTER_HORIZONTAL);
yourCode.setText(R.string.your_confirmation_code);
addView(yourCode);
TextView code = new TextView(ctx);
code.setGravity(CENTER_HORIZONTAL);
code.setTextSize(50);
int localCode = container.getLocalConfirmationCode();
code.setText(String.format("%06d", localCode));
addView(code);
CodeEntryWidget codeEntry = new CodeEntryWidget(ctx);
Resources res = getResources();
codeEntry.init(this, res.getString(R.string.enter_confirmation_code));
addView(codeEntry);
}
public void codeEntered(int remoteCode) {
container.remoteConfirmationCodeEntered(remoteCode);
}
}

View File

@@ -0,0 +1,86 @@
package net.sf.briar.android.invitation;
import static android.view.Gravity.CENTER;
import static android.view.Gravity.CENTER_HORIZONTAL;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import net.sf.briar.R;
import android.content.Context;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class ConnectionFailedView extends AddContactView
implements WifiStateListener, BluetoothStateListener, OnClickListener {
private Button tryAgainButton = null;
ConnectionFailedView(Context ctx) {
super(ctx);
}
void populate() {
removeAllViews();
Context ctx = getContext();
LinearLayout innerLayout = new LinearLayout(ctx);
innerLayout.setOrientation(HORIZONTAL);
innerLayout.setGravity(CENTER);
ImageView icon = new ImageView(ctx);
icon.setPadding(10, 10, 10, 10);
icon.setImageResource(R.drawable.alerts_and_states_error);
innerLayout.addView(icon);
TextView failed = new TextView(ctx);
failed.setTextSize(20);
failed.setText(R.string.connection_failed);
innerLayout.addView(failed);
addView(innerLayout);
TextView checkNetwork = new TextView(ctx);
checkNetwork.setGravity(CENTER_HORIZONTAL);
checkNetwork.setText(R.string.check_same_network);
addView(checkNetwork);
WifiWidget wifi = new WifiWidget(ctx);
wifi.init(this);
addView(wifi);
BluetoothWidget bluetooth = new BluetoothWidget(ctx);
bluetooth.init(this);
addView(bluetooth);
tryAgainButton = new Button(ctx);
LayoutParams lp = new LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
tryAgainButton.setLayoutParams(lp);
tryAgainButton.setText(R.string.try_again_button);
tryAgainButton.setOnClickListener(this);
enabledOrDisableTryAgainButton();
addView(tryAgainButton);
}
public void wifiStateChanged(String networkName) {
container.setNetworkName(networkName);
enabledOrDisableTryAgainButton();
}
public void bluetoothStateChanged(boolean enabled) {
container.setUseBluetooth(enabled);
enabledOrDisableTryAgainButton();
}
private void enabledOrDisableTryAgainButton() {
if(tryAgainButton == null) return; // Activity not created yet
boolean useBluetooth = container.getUseBluetooth();
String networkName = container.getNetworkName();
if(useBluetooth || networkName != null) tryAgainButton.setEnabled(true);
else tryAgainButton.setEnabled(false);
}
public void onClick(View view) {
// Try again
container.reset(new InvitationCodeView(container));
}
}

View File

@@ -0,0 +1,71 @@
package net.sf.briar.android.invitation;
import static android.view.Gravity.CENTER;
import static android.view.Gravity.CENTER_HORIZONTAL;
import net.sf.briar.R;
import android.content.Context;
import android.content.res.Resources;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
public class ConnectionView extends AddContactView {
ConnectionView(Context ctx) {
super(ctx);
}
void populate() {
removeAllViews();
Context ctx = getContext();
TextView yourCode = new TextView(ctx);
yourCode.setGravity(CENTER_HORIZONTAL);
yourCode.setText(R.string.your_invitation_code);
addView(yourCode);
TextView code = new TextView(ctx);
code.setGravity(CENTER_HORIZONTAL);
code.setTextSize(50);
int localCode = container.getLocalInvitationCode();
code.setText(String.format("%06d", localCode));
addView(code);
String networkName = container.getNetworkName();
if(networkName != null) {
LinearLayout innerLayout = new LinearLayout(ctx);
innerLayout.setOrientation(HORIZONTAL);
innerLayout.setGravity(CENTER);
ProgressBar progress = new ProgressBar(ctx);
progress.setIndeterminate(true);
progress.setPadding(0, 10, 10, 0);
innerLayout.addView(progress);
TextView connecting = new TextView(ctx);
Resources res = getResources();
String connectingVia = res.getString(R.string.connecting_wifi);
connecting.setText(String.format(connectingVia, networkName));
innerLayout.addView(connecting);
addView(innerLayout);
}
boolean useBluetooth = container.getUseBluetooth();
if(useBluetooth) {
LinearLayout innerLayout = new LinearLayout(ctx);
innerLayout.setOrientation(HORIZONTAL);
innerLayout.setGravity(CENTER);
ProgressBar progress = new ProgressBar(ctx);
progress.setPadding(0, 10, 10, 0);
progress.setIndeterminate(true);
innerLayout.addView(progress);
TextView connecting = new TextView(ctx);
connecting.setText(R.string.connecting_bluetooth);
innerLayout.addView(connecting);
addView(innerLayout);
}
}
}

View File

@@ -0,0 +1,81 @@
package net.sf.briar.android.invitation;
import static android.view.Gravity.CENTER;
import static android.view.Gravity.CENTER_HORIZONTAL;
import net.sf.briar.R;
import android.content.Context;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
public class ContactAddedView extends AddContactView implements OnClickListener,
OnEditorActionListener {
ContactAddedView(Context ctx) {
super(ctx);
}
void populate() {
removeAllViews();
Context ctx = getContext();
LinearLayout innerLayout = new LinearLayout(ctx);
innerLayout.setOrientation(HORIZONTAL);
innerLayout.setGravity(CENTER);
ImageView icon = new ImageView(ctx);
icon.setImageResource(R.drawable.navigation_accept);
icon.setPadding(10, 10, 10, 10);
innerLayout.addView(icon);
TextView added = new TextView(ctx);
added.setText(R.string.contact_added);
added.setTextSize(20);
innerLayout.addView(added);
addView(innerLayout);
TextView enterNickname = new TextView(ctx);
enterNickname.setGravity(CENTER_HORIZONTAL);
enterNickname.setPadding(0, 0, 0, 10);
enterNickname.setText(R.string.enter_nickname);
addView(enterNickname);
innerLayout = new LinearLayout(ctx);
innerLayout.setOrientation(HORIZONTAL);
innerLayout.setGravity(CENTER);
final Button done = new Button(ctx);
EditText nicknameEntry = new EditText(ctx) {
@Override
protected void onTextChanged(CharSequence text, int start,
int lengthBefore, int lengthAfter) {
done.setEnabled(text.length() > 0);
}
};
nicknameEntry.setMinEms(10);
nicknameEntry.setMaxEms(20);
nicknameEntry.setMaxLines(1);
nicknameEntry.setOnEditorActionListener(this);
innerLayout.addView(nicknameEntry);
done.setText(R.string.done_button);
done.setEnabled(false);
done.setOnClickListener(this);
innerLayout.addView(done);
addView(innerLayout);
}
public boolean onEditorAction(TextView textView, int actionId, KeyEvent e) {
if(textView.getText().length() > 0) container.finish();
return true;
}
public void onClick(View view) {
container.finish(); // Done
}
}

View File

@@ -0,0 +1,40 @@
package net.sf.briar.android.invitation;
import static android.view.Gravity.CENTER_HORIZONTAL;
import net.sf.briar.R;
import android.content.Context;
import android.content.res.Resources;
import android.widget.TextView;
public class InvitationCodeView extends AddContactView
implements CodeEntryListener {
InvitationCodeView(Context ctx) {
super(ctx);
}
void populate() {
removeAllViews();
Context ctx = getContext();
TextView yourCode = new TextView(ctx);
yourCode.setGravity(CENTER_HORIZONTAL);
yourCode.setText(R.string.your_invitation_code);
addView(yourCode);
TextView code = new TextView(ctx);
code.setGravity(CENTER_HORIZONTAL);
code.setTextSize(50);
int localCode = container.getLocalInvitationCode();
code.setText(String.format("%06d", localCode));
addView(code);
CodeEntryWidget codeEntry = new CodeEntryWidget(ctx);
Resources res = getResources();
codeEntry.init(this, res.getString(R.string.enter_invitation_code));
addView(codeEntry);
}
public void codeEntered(int remoteCode) {
container.remoteInvitationCodeEntered(remoteCode);
}
}

View File

@@ -0,0 +1,76 @@
package net.sf.briar.android.invitation;
import static android.view.Gravity.CENTER_HORIZONTAL;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import net.sf.briar.R;
import android.content.Context;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class NetworkSetupView extends AddContactView
implements WifiStateListener, BluetoothStateListener, OnClickListener {
private Button continueButton = null;
NetworkSetupView(Context ctx) {
super(ctx);
}
void populate() {
removeAllViews();
Context ctx = getContext();
TextView sameNetwork = new TextView(ctx);
sameNetwork.setGravity(CENTER_HORIZONTAL);
sameNetwork.setText(R.string.same_network);
addView(sameNetwork);
WifiWidget wifi = new WifiWidget(ctx);
wifi.init(this);
addView(wifi);
BluetoothWidget bluetooth = new BluetoothWidget(ctx);
bluetooth.init(this);
addView(bluetooth);
continueButton = new Button(ctx);
LayoutParams lp = new LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
continueButton.setLayoutParams(lp);
continueButton.setText(R.string.continue_button);
continueButton.setOnClickListener(this);
enableOrDisableContinueButton();
addView(continueButton);
}
public void wifiStateChanged(final String networkName) {
container.runOnUiThread(new Runnable() {
public void run() {
container.setNetworkName(networkName);
enableOrDisableContinueButton();
}
});
}
public void bluetoothStateChanged(final boolean enabled) {
container.runOnUiThread(new Runnable() {
public void run() {
container.setUseBluetooth(enabled);
enableOrDisableContinueButton();
}
});
}
private void enableOrDisableContinueButton() {
if(continueButton == null) return; // Activity not created yet
boolean useBluetooth = container.getUseBluetooth();
String networkName = container.getNetworkName();
if(useBluetooth || networkName != null) continueButton.setEnabled(true);
else continueButton.setEnabled(false);
}
public void onClick(View view) {
// Continue
container.setView(new InvitationCodeView(container));
}
}

View File

@@ -0,0 +1,62 @@
package net.sf.briar.android.invitation;
import static android.view.Gravity.CENTER;
import static android.view.Gravity.CENTER_HORIZONTAL;
import net.sf.briar.R;
import android.content.Context;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
public class WaitForContactView extends AddContactView {
WaitForContactView(Context ctx) {
super(ctx);
}
void populate() {
removeAllViews();
Context ctx = getContext();
LinearLayout innerLayout = new LinearLayout(ctx);
innerLayout.setOrientation(HORIZONTAL);
innerLayout.setGravity(CENTER);
ImageView icon = new ImageView(ctx);
icon.setPadding(10, 10, 10, 10);
icon.setImageResource(R.drawable.navigation_accept);
innerLayout.addView(icon);
TextView failed = new TextView(ctx);
failed.setTextSize(20);
failed.setText(R.string.connected_to_contact);
innerLayout.addView(failed);
addView(innerLayout);
TextView yourCode = new TextView(ctx);
yourCode.setGravity(CENTER_HORIZONTAL);
yourCode.setText(R.string.your_confirmation_code);
addView(yourCode);
TextView code = new TextView(ctx);
code.setGravity(CENTER_HORIZONTAL);
code.setTextSize(50);
int localCode = container.getLocalConfirmationCode();
code.setText(String.format("%06d", localCode));
addView(code);
innerLayout = new LinearLayout(ctx);
innerLayout.setOrientation(HORIZONTAL);
innerLayout.setGravity(CENTER);
ProgressBar progress = new ProgressBar(ctx);
progress.setIndeterminate(true);
progress.setPadding(0, 10, 10, 0);
innerLayout.addView(progress);
TextView connecting = new TextView(ctx);
connecting.setText(R.string.waiting_for_contact);
innerLayout.addView(connecting);
addView(innerLayout);
}
}

View File

@@ -0,0 +1,6 @@
package net.sf.briar.android.invitation;
interface WifiStateListener {
void wifiStateChanged(String networkName);
}

View File

@@ -0,0 +1,102 @@
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 android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import net.sf.briar.R;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class WifiWidget extends LinearLayout implements OnClickListener {
private WifiStateListener listener = null;
public WifiWidget(Context ctx) {
super(ctx);
}
void init(WifiStateListener listener) {
this.listener = listener;
setOrientation(HORIZONTAL);
setGravity(CENTER);
populate();
}
void populate() {
removeAllViews();
Context ctx = getContext();
TextView status = new TextView(ctx);
status.setLayoutParams(new LayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1));
WifiManager wifi = (WifiManager) ctx.getSystemService(WIFI_SERVICE);
if(wifi == null) {
wifiStateChanged(null);
ImageView warning = new ImageView(ctx);
warning.setImageResource(R.drawable.alerts_and_states_warning);
warning.setPadding(10, 10, 10, 10);
addView(warning);
status.setText(R.string.wifi_not_available);
addView(status);
} else if(wifi.isWifiEnabled()) {
WifiInfo info = wifi.getConnectionInfo();
String networkName = info.getSSID();
int networkId = info.getNetworkId();
if(networkName == null || networkId == -1) {
wifiStateChanged(null);
ImageView warning = new ImageView(ctx);
warning.setImageResource(R.drawable.alerts_and_states_warning);
warning.setPadding(10, 10, 10, 10);
addView(warning);
status.setText(R.string.wifi_disconnected);
addView(status);
ImageButton settings = new ImageButton(ctx);
settings.setImageResource(R.drawable.action_settings);
settings.setOnClickListener(this);
addView(settings);
} else {
wifiStateChanged(networkName);
ImageView ok = new ImageView(ctx);
ok.setImageResource(R.drawable.navigation_accept);
ok.setPadding(10, 10, 10, 10);
addView(ok);
Resources res = getResources();
String connected = res.getString(R.string.wifi_connected);
status.setText(String.format(connected, networkName));
addView(status);
ImageButton settings = new ImageButton(ctx);
settings.setImageResource(R.drawable.action_settings);
settings.setOnClickListener(this);
addView(settings);
}
} else {
wifiStateChanged(null);
ImageView warning = new ImageView(ctx);
warning.setImageResource(R.drawable.alerts_and_states_warning);
warning.setPadding(10, 10, 10, 10);
addView(warning);
status.setText(R.string.wifi_disabled);
addView(status);
ImageButton settings = new ImageButton(ctx);
settings.setImageResource(R.drawable.action_settings);
settings.setOnClickListener(this);
addView(settings);
}
}
private void wifiStateChanged(String networkName) {
if(listener != null) listener.wifiStateChanged(networkName);
}
public void onClick(View view) {
getContext().startActivity(new Intent(ACTION_WIFI_SETTINGS));
}
}