mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-21 15:19:53 +01:00
Whitespace-only code formatting changes.
This commit is contained in:
@@ -42,11 +42,11 @@ class AndroidExecutorImpl implements AndroidExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void startIfNecessary() {
|
private void startIfNecessary() {
|
||||||
if(started.getAndSet(true)) return;
|
if (started.getAndSet(true)) return;
|
||||||
new Thread(loop, "AndroidExecutor").start();
|
new Thread(loop, "AndroidExecutor").start();
|
||||||
try {
|
try {
|
||||||
startLatch.await();
|
startLatch.await();
|
||||||
} catch(InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.warning("Interrupted while starting executor thread");
|
LOG.warning("Interrupted while starting executor thread");
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ class AndroidExecutorImpl implements AndroidExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
if(handler != null) {
|
if (handler != null) {
|
||||||
Message m = Message.obtain(handler, SHUTDOWN);
|
Message m = Message.obtain(handler, SHUTDOWN);
|
||||||
handler.sendMessage(m);
|
handler.sendMessage(m);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,8 +94,8 @@ Service, EventListener {
|
|||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
settings = db.getSettings();
|
settings = db.getSettings();
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,14 +108,14 @@ Service, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if(e instanceof SettingsUpdatedEvent) loadSettings();
|
if (e instanceof SettingsUpdatedEvent) loadSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showPrivateMessageNotification(ContactId c) {
|
public void showPrivateMessageNotification(ContactId c) {
|
||||||
synchLock.lock();
|
synchLock.lock();
|
||||||
try {
|
try {
|
||||||
Integer count = contactCounts.get(c);
|
Integer count = contactCounts.get(c);
|
||||||
if(count == null) contactCounts.put(c, 1);
|
if (count == null) contactCounts.put(c, 1);
|
||||||
else contactCounts.put(c, count + 1);
|
else contactCounts.put(c, count + 1);
|
||||||
privateTotal++;
|
privateTotal++;
|
||||||
updatePrivateMessageNotification();
|
updatePrivateMessageNotification();
|
||||||
@@ -128,7 +128,7 @@ Service, EventListener {
|
|||||||
synchLock.lock();
|
synchLock.lock();
|
||||||
try {
|
try {
|
||||||
Integer count = contactCounts.remove(c);
|
Integer count = contactCounts.remove(c);
|
||||||
if(count == null) return; // Already cleared
|
if (count == null) return; // Already cleared
|
||||||
privateTotal -= count;
|
privateTotal -= count;
|
||||||
updatePrivateMessageNotification();
|
updatePrivateMessageNotification();
|
||||||
} finally {
|
} finally {
|
||||||
@@ -138,9 +138,9 @@ Service, EventListener {
|
|||||||
|
|
||||||
// Locking: synchLock
|
// Locking: synchLock
|
||||||
private void updatePrivateMessageNotification() {
|
private void updatePrivateMessageNotification() {
|
||||||
if(privateTotal == 0) {
|
if (privateTotal == 0) {
|
||||||
clearPrivateMessageNotification();
|
clearPrivateMessageNotification();
|
||||||
} else if(!settings.getBoolean("notifyPrivateMessages", true)) {
|
} else if (!settings.getBoolean("notifyPrivateMessages", true)) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
NotificationCompat.Builder b =
|
NotificationCompat.Builder b =
|
||||||
@@ -152,12 +152,12 @@ Service, EventListener {
|
|||||||
privateTotal));
|
privateTotal));
|
||||||
boolean sound = settings.getBoolean("notifySound", true);
|
boolean sound = settings.getBoolean("notifySound", true);
|
||||||
String ringtoneUri = settings.get("notifyRingtoneUri");
|
String ringtoneUri = settings.get("notifyRingtoneUri");
|
||||||
if(sound && !StringUtils.isNullOrEmpty(ringtoneUri))
|
if (sound && !StringUtils.isNullOrEmpty(ringtoneUri))
|
||||||
b.setSound(Uri.parse(ringtoneUri));
|
b.setSound(Uri.parse(ringtoneUri));
|
||||||
b.setDefaults(getDefaults());
|
b.setDefaults(getDefaults());
|
||||||
b.setOnlyAlertOnce(true);
|
b.setOnlyAlertOnce(true);
|
||||||
b.setAutoCancel(true);
|
b.setAutoCancel(true);
|
||||||
if(contactCounts.size() == 1) {
|
if (contactCounts.size() == 1) {
|
||||||
Intent i = new Intent(appContext, ConversationActivity.class);
|
Intent i = new Intent(appContext, ConversationActivity.class);
|
||||||
ContactId c = contactCounts.keySet().iterator().next();
|
ContactId c = contactCounts.keySet().iterator().next();
|
||||||
i.putExtra("briar.CONTACT_ID", c.getInt());
|
i.putExtra("briar.CONTACT_ID", c.getInt());
|
||||||
@@ -192,9 +192,9 @@ Service, EventListener {
|
|||||||
int defaults = DEFAULT_LIGHTS;
|
int defaults = DEFAULT_LIGHTS;
|
||||||
boolean sound = settings.getBoolean("notifySound", true);
|
boolean sound = settings.getBoolean("notifySound", true);
|
||||||
String ringtoneUri = settings.get("notifyRingtoneUri");
|
String ringtoneUri = settings.get("notifyRingtoneUri");
|
||||||
if(sound && StringUtils.isNullOrEmpty(ringtoneUri))
|
if (sound && StringUtils.isNullOrEmpty(ringtoneUri))
|
||||||
defaults |= DEFAULT_SOUND;
|
defaults |= DEFAULT_SOUND;
|
||||||
if(settings.getBoolean("notifyVibration", true))
|
if (settings.getBoolean("notifyVibration", true))
|
||||||
defaults |= DEFAULT_VIBRATE;
|
defaults |= DEFAULT_VIBRATE;
|
||||||
return defaults;
|
return defaults;
|
||||||
}
|
}
|
||||||
@@ -203,7 +203,7 @@ Service, EventListener {
|
|||||||
synchLock.lock();
|
synchLock.lock();
|
||||||
try {
|
try {
|
||||||
Integer count = groupCounts.get(g);
|
Integer count = groupCounts.get(g);
|
||||||
if(count == null) groupCounts.put(g, 1);
|
if (count == null) groupCounts.put(g, 1);
|
||||||
else groupCounts.put(g, count + 1);
|
else groupCounts.put(g, count + 1);
|
||||||
groupTotal++;
|
groupTotal++;
|
||||||
updateGroupPostNotification();
|
updateGroupPostNotification();
|
||||||
@@ -216,7 +216,7 @@ Service, EventListener {
|
|||||||
synchLock.lock();
|
synchLock.lock();
|
||||||
try {
|
try {
|
||||||
Integer count = groupCounts.remove(g);
|
Integer count = groupCounts.remove(g);
|
||||||
if(count == null) return; // Already cleared
|
if (count == null) return; // Already cleared
|
||||||
groupTotal -= count;
|
groupTotal -= count;
|
||||||
updateGroupPostNotification();
|
updateGroupPostNotification();
|
||||||
} finally {
|
} finally {
|
||||||
@@ -226,9 +226,9 @@ Service, EventListener {
|
|||||||
|
|
||||||
// Locking: synchLock
|
// Locking: synchLock
|
||||||
private void updateGroupPostNotification() {
|
private void updateGroupPostNotification() {
|
||||||
if(groupTotal == 0) {
|
if (groupTotal == 0) {
|
||||||
clearGroupPostNotification();
|
clearGroupPostNotification();
|
||||||
} else if(!settings.getBoolean("notifyGroupPosts", true)) {
|
} else if (!settings.getBoolean("notifyGroupPosts", true)) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
NotificationCompat.Builder b =
|
NotificationCompat.Builder b =
|
||||||
@@ -239,12 +239,12 @@ Service, EventListener {
|
|||||||
R.plurals.forum_post_notification_text, groupTotal,
|
R.plurals.forum_post_notification_text, groupTotal,
|
||||||
groupTotal));
|
groupTotal));
|
||||||
String ringtoneUri = settings.get("notifyRingtoneUri");
|
String ringtoneUri = settings.get("notifyRingtoneUri");
|
||||||
if(!StringUtils.isNullOrEmpty(ringtoneUri))
|
if (!StringUtils.isNullOrEmpty(ringtoneUri))
|
||||||
b.setSound(Uri.parse(ringtoneUri));
|
b.setSound(Uri.parse(ringtoneUri));
|
||||||
b.setDefaults(getDefaults());
|
b.setDefaults(getDefaults());
|
||||||
b.setOnlyAlertOnce(true);
|
b.setOnlyAlertOnce(true);
|
||||||
b.setAutoCancel(true);
|
b.setAutoCancel(true);
|
||||||
if(groupCounts.size() == 1) {
|
if (groupCounts.size() == 1) {
|
||||||
Intent i = new Intent(appContext, GroupActivity.class);
|
Intent i = new Intent(appContext, GroupActivity.class);
|
||||||
GroupId g = groupCounts.keySet().iterator().next();
|
GroupId g = groupCounts.keySet().iterator().next();
|
||||||
i.putExtra("briar.GROUP_ID", g.getBytes());
|
i.putExtra("briar.GROUP_ID", g.getBytes());
|
||||||
|
|||||||
@@ -45,15 +45,15 @@ public class BriarActivity extends RoboActivity {
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle state) {
|
public void onCreate(Bundle state) {
|
||||||
super.onCreate(state);
|
super.onCreate(state);
|
||||||
if(PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE);
|
if (PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE);
|
||||||
if(databaseConfig.getEncryptionKey() != null) startAndBindService();
|
if (databaseConfig.getEncryptionKey() != null) startAndBindService();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onActivityResult(int request, int result, Intent data) {
|
protected void onActivityResult(int request, int result, Intent data) {
|
||||||
super.onActivityResult(request, result, data);
|
super.onActivityResult(request, result, data);
|
||||||
if(request == REQUEST_PASSWORD) {
|
if (request == REQUEST_PASSWORD) {
|
||||||
if(result == RESULT_OK) startAndBindService();
|
if (result == RESULT_OK) startAndBindService();
|
||||||
else finish();
|
else finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,7 @@ public class BriarActivity extends RoboActivity {
|
|||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
if(databaseConfig.getEncryptionKey() == null && !isFinishing()) {
|
if (databaseConfig.getEncryptionKey() == null && !isFinishing()) {
|
||||||
Intent i = new Intent(this, PasswordActivity.class);
|
Intent i = new Intent(this, PasswordActivity.class);
|
||||||
i.setFlags(FLAG_ACTIVITY_NO_ANIMATION | FLAG_ACTIVITY_SINGLE_TOP);
|
i.setFlags(FLAG_ACTIVITY_NO_ANIMATION | FLAG_ACTIVITY_SINGLE_TOP);
|
||||||
startActivityForResult(i, REQUEST_PASSWORD);
|
startActivityForResult(i, REQUEST_PASSWORD);
|
||||||
@@ -81,7 +81,7 @@ public class BriarActivity extends RoboActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void unbindService() {
|
private void unbindService() {
|
||||||
if(bound) unbindService(serviceConnection);
|
if (bound) unbindService(serviceConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void signOut() {
|
protected void signOut() {
|
||||||
@@ -97,7 +97,7 @@ public class BriarActivity extends RoboActivity {
|
|||||||
LOG.info("Shutting down service");
|
LOG.info("Shutting down service");
|
||||||
service.shutdown();
|
service.shutdown();
|
||||||
service.waitForShutdown();
|
service.waitForShutdown();
|
||||||
} catch(InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.warning("Interrupted while waiting for service");
|
LOG.warning("Interrupted while waiting for service");
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
@@ -122,7 +122,7 @@ public class BriarActivity extends RoboActivity {
|
|||||||
try {
|
try {
|
||||||
lifecycleManager.waitForDatabase();
|
lifecycleManager.waitForDatabase();
|
||||||
task.run();
|
task.run();
|
||||||
} catch(InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.warning("Interrupted while waiting for database");
|
LOG.warning("Interrupted while waiting for database");
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,12 +66,12 @@ public class BriarService extends RoboService implements EventListener {
|
|||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
LOG.info("Created");
|
LOG.info("Created");
|
||||||
if(created.getAndSet(true)) {
|
if (created.getAndSet(true)) {
|
||||||
LOG.info("Already created");
|
LOG.info("Already created");
|
||||||
stopSelf();
|
stopSelf();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(databaseConfig.getEncryptionKey() == null) {
|
if (databaseConfig.getEncryptionKey() == null) {
|
||||||
LOG.info("No database key");
|
LOG.info("No database key");
|
||||||
stopSelf();
|
stopSelf();
|
||||||
return;
|
return;
|
||||||
@@ -93,14 +93,14 @@ public class BriarService extends RoboService implements EventListener {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
StartResult result = lifecycleManager.startServices();
|
StartResult result = lifecycleManager.startServices();
|
||||||
if(result == SUCCESS) {
|
if (result == SUCCESS) {
|
||||||
eventBus.addListener(BriarService.this);
|
eventBus.addListener(BriarService.this);
|
||||||
started = true;
|
started = true;
|
||||||
} else if(result == ALREADY_RUNNING) {
|
} else if (result == ALREADY_RUNNING) {
|
||||||
LOG.info("Already running");
|
LOG.info("Already running");
|
||||||
stopSelf();
|
stopSelf();
|
||||||
} else {
|
} else {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.warning("Startup failed: " + result);
|
LOG.warning("Startup failed: " + result);
|
||||||
showStartupFailureNotification();
|
showStartupFailureNotification();
|
||||||
stopSelf();
|
stopSelf();
|
||||||
@@ -147,7 +147,7 @@ public class BriarService extends RoboService implements EventListener {
|
|||||||
new Thread() {
|
new Thread() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if(started) {
|
if (started) {
|
||||||
eventBus.removeListener(BriarService.this);
|
eventBus.removeListener(BriarService.this);
|
||||||
lifecycleManager.stopServices();
|
lifecycleManager.stopServices();
|
||||||
}
|
}
|
||||||
@@ -164,11 +164,11 @@ public class BriarService extends RoboService implements EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if(e instanceof MessageAddedEvent) {
|
if (e instanceof MessageAddedEvent) {
|
||||||
MessageAddedEvent m = (MessageAddedEvent) e;
|
MessageAddedEvent m = (MessageAddedEvent) e;
|
||||||
GroupId g = m.getGroup().getId();
|
GroupId g = m.getGroup().getId();
|
||||||
ContactId c = m.getContactId();
|
ContactId c = m.getContactId();
|
||||||
if(c != null) showMessageNotification(g, c);
|
if (c != null) showMessageNotification(g, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,13 +177,13 @@ public class BriarService extends RoboService implements EventListener {
|
|||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
lifecycleManager.waitForDatabase();
|
lifecycleManager.waitForDatabase();
|
||||||
if(g.equals(db.getInboxGroupId(c)))
|
if (g.equals(db.getInboxGroupId(c)))
|
||||||
notificationManager.showPrivateMessageNotification(c);
|
notificationManager.showPrivateMessageNotification(c);
|
||||||
else notificationManager.showGroupPostNotification(g);
|
else notificationManager.showGroupPostNotification(g);
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
} catch(InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.info("Interruped while waiting for database");
|
LOG.info("Interruped while waiting for database");
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,6 @@ class CrashHandler implements UncaughtExceptionHandler {
|
|||||||
i.putExtra("briar.PID", android.os.Process.myPid());
|
i.putExtra("briar.PID", android.os.Process.myPid());
|
||||||
ctx.startActivity(i);
|
ctx.startActivity(i);
|
||||||
// Pass the exception to the default handler, if any
|
// Pass the exception to the default handler, if any
|
||||||
if(delegate != null) delegate.uncaughtException(thread, throwable);
|
if (delegate != null) delegate.uncaughtException(thread, throwable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ public class CrashReportActivity extends Activity implements OnClickListener {
|
|||||||
progress.setVisibility(GONE);
|
progress.setVisibility(GONE);
|
||||||
layout.addView(progress);
|
layout.addView(progress);
|
||||||
|
|
||||||
if(SHARE_CRASH_REPORTS) {
|
if (SHARE_CRASH_REPORTS) {
|
||||||
layout.addView(new HorizontalBorder(this));
|
layout.addView(new HorizontalBorder(this));
|
||||||
LinearLayout footer = new LinearLayout(this);
|
LinearLayout footer = new LinearLayout(this);
|
||||||
footer.setLayoutParams(MATCH_WRAP);
|
footer.setLayoutParams(MATCH_WRAP);
|
||||||
@@ -143,7 +143,7 @@ public class CrashReportActivity extends Activity implements OnClickListener {
|
|||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
if(temp != null) temp.delete();
|
if (temp != null) temp.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
@@ -165,7 +165,7 @@ public class CrashReportActivity extends Activity implements OnClickListener {
|
|||||||
protected void onPostExecute(Map<String, String> result) {
|
protected void onPostExecute(Map<String, String> result) {
|
||||||
Context ctx = CrashReportActivity.this;
|
Context ctx = CrashReportActivity.this;
|
||||||
int pad = LayoutUtils.getPadding(ctx);
|
int pad = LayoutUtils.getPadding(ctx);
|
||||||
for(Entry<String, String> e : result.entrySet()) {
|
for (Entry<String, String> e : result.entrySet()) {
|
||||||
TextView title = new TextView(ctx);
|
TextView title = new TextView(ctx);
|
||||||
title.setTextSize(18);
|
title.setTextSize(18);
|
||||||
title.setText(e.getKey());
|
title.setText(e.getKey());
|
||||||
@@ -191,9 +191,9 @@ public class CrashReportActivity extends Activity implements OnClickListener {
|
|||||||
String manufacturer = Build.MANUFACTURER;
|
String manufacturer = Build.MANUFACTURER;
|
||||||
String model = Build.MODEL;
|
String model = Build.MODEL;
|
||||||
String brand = Build.BRAND;
|
String brand = Build.BRAND;
|
||||||
if(model.startsWith(manufacturer)) deviceType = capitalize(model);
|
if (model.startsWith(manufacturer)) deviceType = capitalize(model);
|
||||||
else deviceType = capitalize(manufacturer) + " " + model;
|
else deviceType = capitalize(manufacturer) + " " + model;
|
||||||
if(!StringUtils.isNullOrEmpty(brand))
|
if (!StringUtils.isNullOrEmpty(brand))
|
||||||
deviceType += " (" + capitalize(brand) + ")";
|
deviceType += " (" + capitalize(brand) + ")";
|
||||||
statusMap.put("Device type:", deviceType);
|
statusMap.put("Device type:", deviceType);
|
||||||
|
|
||||||
@@ -213,7 +213,7 @@ public class CrashReportActivity extends Activity implements OnClickListener {
|
|||||||
ActivityManager.MemoryInfo mem = new ActivityManager.MemoryInfo();
|
ActivityManager.MemoryInfo mem = new ActivityManager.MemoryInfo();
|
||||||
am.getMemoryInfo(mem);
|
am.getMemoryInfo(mem);
|
||||||
String systemMemory;
|
String systemMemory;
|
||||||
if(Build.VERSION.SDK_INT >= 16) {
|
if (Build.VERSION.SDK_INT >= 16) {
|
||||||
systemMemory = (mem.totalMem / 1024 / 1024) + " MiB total, "
|
systemMemory = (mem.totalMem / 1024 / 1024) + " MiB total, "
|
||||||
+ (mem.availMem / 1024 / 1204) + " MiB free, "
|
+ (mem.availMem / 1024 / 1204) + " MiB free, "
|
||||||
+ (mem.threshold / 1024 / 1024) + " MiB threshold";
|
+ (mem.threshold / 1024 / 1024) + " MiB threshold";
|
||||||
@@ -241,7 +241,7 @@ public class CrashReportActivity extends Activity implements OnClickListener {
|
|||||||
String internal = (rootTotal / 1024 / 1024) + " MiB total, "
|
String internal = (rootTotal / 1024 / 1024) + " MiB total, "
|
||||||
+ (rootFree / 1024 / 1024) + " MiB free";
|
+ (rootFree / 1024 / 1024) + " MiB free";
|
||||||
statusMap.put("Internal storage:", internal);
|
statusMap.put("Internal storage:", internal);
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
statusMap.put("Internal storage:", "Unknown");
|
statusMap.put("Internal storage:", "Unknown");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,7 +253,7 @@ public class CrashReportActivity extends Activity implements OnClickListener {
|
|||||||
String external = (sdTotal / 1024 / 1024) + " MiB total, "
|
String external = (sdTotal / 1024 / 1024) + " MiB total, "
|
||||||
+ (sdFree / 1024 / 1024) + " MiB free";
|
+ (sdFree / 1024 / 1024) + " MiB free";
|
||||||
statusMap.put("External storage:", external);
|
statusMap.put("External storage:", external);
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
statusMap.put("External storage:", "Unknown");
|
statusMap.put("External storage:", "Unknown");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,26 +269,26 @@ public class CrashReportActivity extends Activity implements OnClickListener {
|
|||||||
Method method = clazz.getDeclaredMethod("getMobileDataEnabled");
|
Method method = clazz.getDeclaredMethod("getMobileDataEnabled");
|
||||||
method.setAccessible(true);
|
method.setAccessible(true);
|
||||||
mobileEnabled = (Boolean) method.invoke(cm);
|
mobileEnabled = (Boolean) method.invoke(cm);
|
||||||
} catch(ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
} catch(NoSuchMethodException e) {
|
} catch (NoSuchMethodException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
} catch(IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
} catch(IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
} catch(InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
// Is mobile data connected ?
|
// Is mobile data connected ?
|
||||||
boolean mobileConnected = mobile != null && mobile.isConnected();
|
boolean mobileConnected = mobile != null && mobile.isConnected();
|
||||||
|
|
||||||
String mobileStatus;
|
String mobileStatus;
|
||||||
if(mobileAvailable) mobileStatus = "Available, ";
|
if (mobileAvailable) mobileStatus = "Available, ";
|
||||||
else mobileStatus = "Not available, ";
|
else mobileStatus = "Not available, ";
|
||||||
if(mobileEnabled) mobileStatus += "enabled, ";
|
if (mobileEnabled) mobileStatus += "enabled, ";
|
||||||
else mobileStatus += "not enabled, ";
|
else mobileStatus += "not enabled, ";
|
||||||
if(mobileConnected) mobileStatus += "connected";
|
if (mobileConnected) mobileStatus += "connected";
|
||||||
else mobileStatus += "not connected";
|
else mobileStatus += "not connected";
|
||||||
statusMap.put("Mobile data:", mobileStatus);
|
statusMap.put("Mobile data:", mobileStatus);
|
||||||
|
|
||||||
@@ -303,15 +303,15 @@ public class CrashReportActivity extends Activity implements OnClickListener {
|
|||||||
boolean wifiConnected = wifi != null && wifi.isConnected();
|
boolean wifiConnected = wifi != null && wifi.isConnected();
|
||||||
|
|
||||||
String wifiStatus;
|
String wifiStatus;
|
||||||
if(wifiAvailable) wifiStatus = "Available, ";
|
if (wifiAvailable) wifiStatus = "Available, ";
|
||||||
else wifiStatus = "Not available, ";
|
else wifiStatus = "Not available, ";
|
||||||
if(wifiEnabled) wifiStatus += "enabled, ";
|
if (wifiEnabled) wifiStatus += "enabled, ";
|
||||||
else wifiStatus += "not enabled, ";
|
else wifiStatus += "not enabled, ";
|
||||||
if(wifiConnected) wifiStatus += "connected";
|
if (wifiConnected) wifiStatus += "connected";
|
||||||
else wifiStatus += "not connected";
|
else wifiStatus += "not connected";
|
||||||
if(wm != null) {
|
if (wm != null) {
|
||||||
WifiInfo wifiInfo = wm.getConnectionInfo();
|
WifiInfo wifiInfo = wm.getConnectionInfo();
|
||||||
if(wifiInfo != null) {
|
if (wifiInfo != null) {
|
||||||
int ip = wifiInfo.getIpAddress(); // Nice API, Google
|
int ip = wifiInfo.getIpAddress(); // Nice API, Google
|
||||||
int ip1 = ip & 0xFF;
|
int ip1 = ip & 0xFF;
|
||||||
int ip2 = (ip >> 8) & 0xFF;
|
int ip2 = (ip >> 8) & 0xFF;
|
||||||
@@ -331,11 +331,11 @@ public class CrashReportActivity extends Activity implements OnClickListener {
|
|||||||
return BluetoothAdapter.getDefaultAdapter();
|
return BluetoothAdapter.getDefaultAdapter();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch(InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.warning("Interrupted while getting BluetoothAdapter");
|
LOG.warning("Interrupted while getting BluetoothAdapter");
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
} catch(ExecutionException e) {
|
} catch (ExecutionException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
boolean btAvailable = bt != null;
|
boolean btAvailable = bt != null;
|
||||||
// Is Bluetooth enabled?
|
// Is Bluetooth enabled?
|
||||||
@@ -350,37 +350,37 @@ public class CrashReportActivity extends Activity implements OnClickListener {
|
|||||||
bt.getScanMode() == SCAN_MODE_CONNECTABLE_DISCOVERABLE;
|
bt.getScanMode() == SCAN_MODE_CONNECTABLE_DISCOVERABLE;
|
||||||
|
|
||||||
String btStatus;
|
String btStatus;
|
||||||
if(btAvailable) btStatus = "Available, ";
|
if (btAvailable) btStatus = "Available, ";
|
||||||
else btStatus = "Not available, ";
|
else btStatus = "Not available, ";
|
||||||
if(btEnabled) btStatus += "enabled, ";
|
if (btEnabled) btStatus += "enabled, ";
|
||||||
else btStatus += "not enabled, ";
|
else btStatus += "not enabled, ";
|
||||||
if(btConnectable) btStatus += "connectable, ";
|
if (btConnectable) btStatus += "connectable, ";
|
||||||
else btStatus += "not connectable, ";
|
else btStatus += "not connectable, ";
|
||||||
if(btDiscoverable) btStatus += "discoverable";
|
if (btDiscoverable) btStatus += "discoverable";
|
||||||
else btStatus += "not discoverable";
|
else btStatus += "not discoverable";
|
||||||
if(bt != null) btStatus += "\nAddress: " + bt.getAddress();
|
if (bt != null) btStatus += "\nAddress: " + bt.getAddress();
|
||||||
statusMap.put("Bluetooth:", btStatus);
|
statusMap.put("Bluetooth:", btStatus);
|
||||||
|
|
||||||
// Stack trace
|
// Stack trace
|
||||||
if(stack != null) statusMap.put("Stack trace:", stack);
|
if (stack != null) statusMap.put("Stack trace:", stack);
|
||||||
|
|
||||||
// All log output from the crashed process
|
// All log output from the crashed process
|
||||||
if(pid != -1) {
|
if (pid != -1) {
|
||||||
StringBuilder log = new StringBuilder();
|
StringBuilder log = new StringBuilder();
|
||||||
try {
|
try {
|
||||||
Pattern pattern = Pattern.compile(".*\\( *" + pid + "\\).*");
|
Pattern pattern = Pattern.compile(".*\\( *" + pid + "\\).*");
|
||||||
Process process = runtime.exec("logcat -d -v time *:I");
|
Process process = runtime.exec("logcat -d -v time *:I");
|
||||||
Scanner scanner = new Scanner(process.getInputStream());
|
Scanner scanner = new Scanner(process.getInputStream());
|
||||||
while(scanner.hasNextLine()) {
|
while (scanner.hasNextLine()) {
|
||||||
String line = scanner.nextLine();
|
String line = scanner.nextLine();
|
||||||
if(pattern.matcher(line).matches()) {
|
if (pattern.matcher(line).matches()) {
|
||||||
log.append(line);
|
log.append(line);
|
||||||
log.append('\n');
|
log.append('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scanner.close();
|
scanner.close();
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
statusMap.put("Debugging log:", log.toString());
|
statusMap.put("Debugging log:", log.toString());
|
||||||
}
|
}
|
||||||
@@ -389,9 +389,9 @@ public class CrashReportActivity extends Activity implements OnClickListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String capitalize(String s) {
|
private String capitalize(String s) {
|
||||||
if(StringUtils.isNullOrEmpty(s)) return s;
|
if (StringUtils.isNullOrEmpty(s)) return s;
|
||||||
char first = s.charAt(0);
|
char first = s.charAt(0);
|
||||||
if(Character.isUpperCase(first)) return s;
|
if (Character.isUpperCase(first)) return s;
|
||||||
return Character.toUpperCase(first) + s.substring(1);
|
return Character.toUpperCase(first) + s.substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,10 +408,10 @@ public class CrashReportActivity extends Activity implements OnClickListener {
|
|||||||
try {
|
try {
|
||||||
File shared = Environment.getExternalStorageDirectory();
|
File shared = Environment.getExternalStorageDirectory();
|
||||||
temp = File.createTempFile("crash", ".txt", shared);
|
temp = File.createTempFile("crash", ".txt", shared);
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Writing to " + temp.getPath());
|
LOG.info("Writing to " + temp.getPath());
|
||||||
PrintStream p = new PrintStream(new FileOutputStream(temp));
|
PrintStream p = new PrintStream(new FileOutputStream(temp));
|
||||||
for(Entry<String, String> e : result.entrySet()) {
|
for (Entry<String, String> e : result.entrySet()) {
|
||||||
p.println(e.getKey());
|
p.println(e.getKey());
|
||||||
p.println(e.getValue());
|
p.println(e.getValue());
|
||||||
p.println();
|
p.println();
|
||||||
@@ -419,8 +419,8 @@ public class CrashReportActivity extends Activity implements OnClickListener {
|
|||||||
p.flush();
|
p.flush();
|
||||||
p.close();
|
p.close();
|
||||||
sendEmail(Uri.fromFile(temp));
|
sendEmail(Uri.fromFile(temp));
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,11 +59,11 @@ public class DashboardActivity extends BriarActivity {
|
|||||||
private void handleIntent(Intent i) {
|
private void handleIntent(Intent i) {
|
||||||
boolean failed = i.getBooleanExtra("briar.STARTUP_FAILED", false);
|
boolean failed = i.getBooleanExtra("briar.STARTUP_FAILED", false);
|
||||||
long handle = i.getLongExtra("briar.LOCAL_AUTHOR_HANDLE", -1);
|
long handle = i.getLongExtra("briar.LOCAL_AUTHOR_HANDLE", -1);
|
||||||
if(failed) {
|
if (failed) {
|
||||||
finish();
|
finish();
|
||||||
LOG.info("Exiting");
|
LOG.info("Exiting");
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
} else if(handle == -1) {
|
} else if (handle == -1) {
|
||||||
// The activity has been launched before
|
// The activity has been launched before
|
||||||
showButtons();
|
showButtons();
|
||||||
} else {
|
} else {
|
||||||
@@ -72,7 +72,7 @@ public class DashboardActivity extends BriarActivity {
|
|||||||
LocalAuthor.class);
|
LocalAuthor.class);
|
||||||
// The reference may be null if the activity has been recreated,
|
// The reference may be null if the activity has been recreated,
|
||||||
// for example due to screen rotation
|
// for example due to screen rotation
|
||||||
if(a == null) {
|
if (a == null) {
|
||||||
showButtons();
|
showButtons();
|
||||||
} else {
|
} else {
|
||||||
showSpinner();
|
showSpinner();
|
||||||
@@ -192,15 +192,15 @@ public class DashboardActivity extends BriarActivity {
|
|||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
db.addLocalAuthor(a);
|
db.addLocalAuthor(a);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Storing author took " + duration + " ms");
|
LOG.info("Storing author took " + duration + " ms");
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
showButtons();
|
showButtons();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public class ExpiredActivity extends Activity {
|
|||||||
public void onCreate(Bundle state) {
|
public void onCreate(Bundle state) {
|
||||||
super.onCreate(state);
|
super.onCreate(state);
|
||||||
|
|
||||||
if(PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE);
|
if (PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE);
|
||||||
|
|
||||||
LinearLayout layout = new LinearLayout(this);
|
LinearLayout layout = new LinearLayout(this);
|
||||||
layout.setLayoutParams(MATCH_MATCH);
|
layout.setLayoutParams(MATCH_MATCH);
|
||||||
|
|||||||
@@ -58,11 +58,11 @@ public class PasswordActivity extends RoboActivity {
|
|||||||
public void onCreate(Bundle state) {
|
public void onCreate(Bundle state) {
|
||||||
super.onCreate(state);
|
super.onCreate(state);
|
||||||
|
|
||||||
if(PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE);
|
if (PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE);
|
||||||
|
|
||||||
SharedPreferences prefs = getSharedPreferences("db", MODE_PRIVATE);
|
SharedPreferences prefs = getSharedPreferences("db", MODE_PRIVATE);
|
||||||
String hex = prefs.getString("key", null);
|
String hex = prefs.getString("key", null);
|
||||||
if(hex == null || !databaseConfig.databaseExists()) {
|
if (hex == null || !databaseConfig.databaseExists()) {
|
||||||
// Storage has been deleted - clean up and return to setup
|
// Storage has been deleted - clean up and return to setup
|
||||||
prefs.edit().clear().commit();
|
prefs.edit().clear().commit();
|
||||||
delete(databaseConfig.getDatabaseDirectory());
|
delete(databaseConfig.getDatabaseDirectory());
|
||||||
@@ -121,12 +121,12 @@ public class PasswordActivity extends RoboActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void delete(File f) {
|
private void delete(File f) {
|
||||||
if(f.isFile()) f.delete();
|
if (f.isFile()) f.delete();
|
||||||
else if(f.isDirectory()) for(File child : f.listFiles()) delete(child);
|
else if (f.isDirectory()) for (File child : f.listFiles()) delete(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validatePassword(final byte[] encrypted, Editable e) {
|
private void validatePassword(final byte[] encrypted, Editable e) {
|
||||||
if(progress == null) return; // Not created yet
|
if (progress == null) return; // Not created yet
|
||||||
// Hide the soft keyboard
|
// Hide the soft keyboard
|
||||||
Object o = getSystemService(INPUT_METHOD_SERVICE);
|
Object o = getSystemService(INPUT_METHOD_SERVICE);
|
||||||
((InputMethodManager) o).toggleSoftInput(HIDE_IMPLICIT_ONLY, 0);
|
((InputMethodManager) o).toggleSoftInput(HIDE_IMPLICIT_ONLY, 0);
|
||||||
@@ -138,7 +138,7 @@ public class PasswordActivity extends RoboActivity {
|
|||||||
cryptoExecutor.execute(new Runnable() {
|
cryptoExecutor.execute(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
byte[] key = crypto.decryptWithPassword(encrypted, password);
|
byte[] key = crypto.decryptWithPassword(encrypted, password);
|
||||||
if(key == null) {
|
if (key == null) {
|
||||||
tryAgain();
|
tryAgain();
|
||||||
} else {
|
} else {
|
||||||
databaseConfig.setEncryptionKey(new SecretKey(key));
|
databaseConfig.setEncryptionKey(new SecretKey(key));
|
||||||
|
|||||||
@@ -26,12 +26,12 @@ class ReferenceManagerImpl implements ReferenceManager {
|
|||||||
synchLock.lock();
|
synchLock.lock();
|
||||||
try {
|
try {
|
||||||
Map<Long, Object> innerMap = outerMap.get(c);
|
Map<Long, Object> innerMap = outerMap.get(c);
|
||||||
if(innerMap == null) {
|
if (innerMap == null) {
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("0 handles for " + c.getName());
|
LOG.info("0 handles for " + c.getName());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info(innerMap.size() + " handles for " + c.getName());
|
LOG.info(innerMap.size() + " handles for " + c.getName());
|
||||||
Object o = innerMap.get(handle);
|
Object o = innerMap.get(handle);
|
||||||
return c.cast(o);
|
return c.cast(o);
|
||||||
@@ -45,13 +45,13 @@ class ReferenceManagerImpl implements ReferenceManager {
|
|||||||
synchLock.lock();
|
synchLock.lock();
|
||||||
try {
|
try {
|
||||||
Map<Long, Object> innerMap = outerMap.get(c);
|
Map<Long, Object> innerMap = outerMap.get(c);
|
||||||
if(innerMap == null) {
|
if (innerMap == null) {
|
||||||
innerMap = new HashMap<Long, Object>();
|
innerMap = new HashMap<Long, Object>();
|
||||||
outerMap.put(c, innerMap);
|
outerMap.put(c, innerMap);
|
||||||
}
|
}
|
||||||
long handle = nextHandle++;
|
long handle = nextHandle++;
|
||||||
innerMap.put(handle, reference);
|
innerMap.put(handle, reference);
|
||||||
if(LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
LOG.info(innerMap.size() + " handles for " + c.getName() +
|
LOG.info(innerMap.size() + " handles for " + c.getName() +
|
||||||
" after put");
|
" after put");
|
||||||
}
|
}
|
||||||
@@ -65,10 +65,10 @@ class ReferenceManagerImpl implements ReferenceManager {
|
|||||||
synchLock.lock();
|
synchLock.lock();
|
||||||
try {
|
try {
|
||||||
Map<Long, Object> innerMap = outerMap.get(c);
|
Map<Long, Object> innerMap = outerMap.get(c);
|
||||||
if(innerMap == null) return null;
|
if (innerMap == null) return null;
|
||||||
Object o = innerMap.remove(handle);
|
Object o = innerMap.remove(handle);
|
||||||
if(innerMap.isEmpty()) outerMap.remove(c);
|
if (innerMap.isEmpty()) outerMap.remove(c);
|
||||||
if(LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
LOG.info(innerMap.size() + " handles for " + c.getName() +
|
LOG.info(innerMap.size() + " handles for " + c.getName() +
|
||||||
" after remove");
|
" after remove");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ OnClickListener {
|
|||||||
|
|
||||||
layout.addView(new HorizontalBorder(this));
|
layout.addView(new HorizontalBorder(this));
|
||||||
|
|
||||||
if(SHOW_TESTING_ACTIVITY) {
|
if (SHOW_TESTING_ACTIVITY) {
|
||||||
LinearLayout footer = new LinearLayout(this);
|
LinearLayout footer = new LinearLayout(this);
|
||||||
footer.setLayoutParams(MATCH_WRAP);
|
footer.setLayoutParams(MATCH_WRAP);
|
||||||
footer.setGravity(CENTER);
|
footer.setGravity(CENTER);
|
||||||
@@ -215,12 +215,12 @@ OnClickListener {
|
|||||||
TransportConfig c = db.getConfig(new TransportId("bt"));
|
TransportConfig c = db.getConfig(new TransportId("bt"));
|
||||||
settings = db.getSettings();
|
settings = db.getSettings();
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Loading settings took " + duration + " ms");
|
LOG.info("Loading settings took " + duration + " ms");
|
||||||
bluetoothSetting = c.getBoolean("enable", true);
|
bluetoothSetting = c.getBoolean("enable", true);
|
||||||
displaySettings();
|
displaySettings();
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -234,7 +234,7 @@ OnClickListener {
|
|||||||
progress.setVisibility(GONE);
|
progress.setVisibility(GONE);
|
||||||
|
|
||||||
int resId;
|
int resId;
|
||||||
if(bluetoothSetting) resId = R.string.bluetooth_setting_enabled;
|
if (bluetoothSetting) resId = R.string.bluetooth_setting_enabled;
|
||||||
else resId = R.string.bluetooth_setting_disabled;
|
else resId = R.string.bluetooth_setting_disabled;
|
||||||
enableBluetoothHint.setText(resId);
|
enableBluetoothHint.setText(resId);
|
||||||
|
|
||||||
@@ -248,9 +248,9 @@ OnClickListener {
|
|||||||
"notifyVibration", true));
|
"notifyVibration", true));
|
||||||
|
|
||||||
String text;
|
String text;
|
||||||
if(settings.getBoolean("notifySound", true)) {
|
if (settings.getBoolean("notifySound", true)) {
|
||||||
String ringtoneName = settings.get("notifyRingtoneName");
|
String ringtoneName = settings.get("notifyRingtoneName");
|
||||||
if(StringUtils.isNullOrEmpty(ringtoneName))
|
if (StringUtils.isNullOrEmpty(ringtoneName))
|
||||||
text = getString(R.string.notify_sound_setting_default);
|
text = getString(R.string.notify_sound_setting_default);
|
||||||
else text = ringtoneName;
|
else text = ringtoneName;
|
||||||
} else {
|
} else {
|
||||||
@@ -268,43 +268,43 @@ OnClickListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
if(progress == null) return; // Not created yet
|
if (progress == null) return; // Not created yet
|
||||||
if(view == testingButton) {
|
if (view == testingButton) {
|
||||||
startActivity(new Intent(this, TestingActivity.class));
|
startActivity(new Intent(this, TestingActivity.class));
|
||||||
} else if(view == enableBluetooth || view == enableBluetoothHint) {
|
} else if (view == enableBluetooth || view == enableBluetoothHint) {
|
||||||
bluetoothSetting = !bluetoothSetting;
|
bluetoothSetting = !bluetoothSetting;
|
||||||
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||||
if(adapter != null) {
|
if (adapter != null) {
|
||||||
if(bluetoothSetting) adapter.enable();
|
if (bluetoothSetting) adapter.enable();
|
||||||
else adapter.disable();
|
else adapter.disable();
|
||||||
}
|
}
|
||||||
storeBluetoothSetting();
|
storeBluetoothSetting();
|
||||||
displaySettings();
|
displaySettings();
|
||||||
return;
|
return;
|
||||||
} else if(view == notifyPrivateMessages) {
|
} else if (view == notifyPrivateMessages) {
|
||||||
Settings s = new Settings();
|
Settings s = new Settings();
|
||||||
s.putBoolean("notifyPrivateMessages",
|
s.putBoolean("notifyPrivateMessages",
|
||||||
notifyPrivateMessages.isChecked());
|
notifyPrivateMessages.isChecked());
|
||||||
storeSettings(s);
|
storeSettings(s);
|
||||||
} else if(view == notifyGroupPosts) {
|
} else if (view == notifyGroupPosts) {
|
||||||
Settings s = new Settings();
|
Settings s = new Settings();
|
||||||
s.putBoolean("notifyGroupPosts", notifyGroupPosts.isChecked());
|
s.putBoolean("notifyGroupPosts", notifyGroupPosts.isChecked());
|
||||||
storeSettings(s);
|
storeSettings(s);
|
||||||
} else if(view == notifyVibration) {
|
} else if (view == notifyVibration) {
|
||||||
Settings s = new Settings();
|
Settings s = new Settings();
|
||||||
s.putBoolean("notifyVibration", notifyVibration.isChecked());
|
s.putBoolean("notifyVibration", notifyVibration.isChecked());
|
||||||
storeSettings(s);
|
storeSettings(s);
|
||||||
} else if(view == notifySound || view == notifySoundHint) {
|
} else if (view == notifySound || view == notifySoundHint) {
|
||||||
String title = getString(R.string.choose_ringtone_title);
|
String title = getString(R.string.choose_ringtone_title);
|
||||||
Intent i = new Intent(ACTION_RINGTONE_PICKER);
|
Intent i = new Intent(ACTION_RINGTONE_PICKER);
|
||||||
i.putExtra(EXTRA_RINGTONE_TYPE, TYPE_NOTIFICATION);
|
i.putExtra(EXTRA_RINGTONE_TYPE, TYPE_NOTIFICATION);
|
||||||
i.putExtra(EXTRA_RINGTONE_TITLE, title);
|
i.putExtra(EXTRA_RINGTONE_TITLE, title);
|
||||||
i.putExtra(EXTRA_RINGTONE_DEFAULT_URI, DEFAULT_NOTIFICATION_URI);
|
i.putExtra(EXTRA_RINGTONE_DEFAULT_URI, DEFAULT_NOTIFICATION_URI);
|
||||||
i.putExtra(EXTRA_RINGTONE_SHOW_SILENT, true);
|
i.putExtra(EXTRA_RINGTONE_SHOW_SILENT, true);
|
||||||
if(settings.getBoolean("notifySound", true)) {
|
if (settings.getBoolean("notifySound", true)) {
|
||||||
Uri uri;
|
Uri uri;
|
||||||
String ringtoneUri = settings.get("notifyRingtoneUri");
|
String ringtoneUri = settings.get("notifyRingtoneUri");
|
||||||
if(StringUtils.isNullOrEmpty(ringtoneUri))
|
if (StringUtils.isNullOrEmpty(ringtoneUri))
|
||||||
uri = DEFAULT_NOTIFICATION_URI;
|
uri = DEFAULT_NOTIFICATION_URI;
|
||||||
else uri = Uri.parse(ringtoneUri);
|
else uri = Uri.parse(ringtoneUri);
|
||||||
i.putExtra(EXTRA_RINGTONE_EXISTING_URI, uri);
|
i.putExtra(EXTRA_RINGTONE_EXISTING_URI, uri);
|
||||||
@@ -322,10 +322,10 @@ OnClickListener {
|
|||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
db.mergeConfig(new TransportId("bt"), c);
|
db.mergeConfig(new TransportId("bt"), c);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Merging config took " + duration + " ms");
|
LOG.info("Merging config took " + duration + " ms");
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -339,10 +339,10 @@ OnClickListener {
|
|||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
db.mergeSettings(settings);
|
db.mergeSettings(settings);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Merging settings took " + duration + " ms");
|
LOG.info("Merging settings took " + duration + " ms");
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -352,16 +352,16 @@ OnClickListener {
|
|||||||
@Override
|
@Override
|
||||||
public void onActivityResult(int request, int result, Intent data) {
|
public void onActivityResult(int request, int result, Intent data) {
|
||||||
super.onActivityResult(request, result, data);
|
super.onActivityResult(request, result, data);
|
||||||
if(request == REQUEST_RINGTONE && result == RESULT_OK) {
|
if (request == REQUEST_RINGTONE && result == RESULT_OK) {
|
||||||
Settings s = new Settings();
|
Settings s = new Settings();
|
||||||
Uri uri = data.getParcelableExtra(EXTRA_RINGTONE_PICKED_URI);
|
Uri uri = data.getParcelableExtra(EXTRA_RINGTONE_PICKED_URI);
|
||||||
if(uri == null) {
|
if (uri == null) {
|
||||||
// The user chose silence
|
// The user chose silence
|
||||||
notifySoundHint.setText(R.string.notify_sound_setting_disabled);
|
notifySoundHint.setText(R.string.notify_sound_setting_disabled);
|
||||||
s.putBoolean("notifySound", false);
|
s.putBoolean("notifySound", false);
|
||||||
s.put("notifyRingtoneName", "");
|
s.put("notifyRingtoneName", "");
|
||||||
s.put("notifyRingtoneUri", "");
|
s.put("notifyRingtoneUri", "");
|
||||||
} else if(RingtoneManager.isDefault(uri)) {
|
} else if (RingtoneManager.isDefault(uri)) {
|
||||||
// The user chose the default
|
// The user chose the default
|
||||||
notifySoundHint.setText(R.string.notify_sound_setting_default);
|
notifySoundHint.setText(R.string.notify_sound_setting_default);
|
||||||
s.putBoolean("notifySound", true);
|
s.putBoolean("notifySound", true);
|
||||||
@@ -381,7 +381,7 @@ OnClickListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if(e instanceof SettingsUpdatedEvent) {
|
if (e instanceof SettingsUpdatedEvent) {
|
||||||
LOG.info("Settings updated");
|
LOG.info("Settings updated");
|
||||||
loadSettings();
|
loadSettings();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ OnEditorActionListener {
|
|||||||
public void onCreate(Bundle state) {
|
public void onCreate(Bundle state) {
|
||||||
super.onCreate(state);
|
super.onCreate(state);
|
||||||
|
|
||||||
if(PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE);
|
if (PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE);
|
||||||
|
|
||||||
LinearLayout layout = new LinearLayout(this);
|
LinearLayout layout = new LinearLayout(this);
|
||||||
layout.setLayoutParams(MATCH_MATCH);
|
layout.setLayoutParams(MATCH_MATCH);
|
||||||
@@ -181,8 +181,8 @@ OnEditorActionListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void enableOrDisableContinueButton() {
|
private void enableOrDisableContinueButton() {
|
||||||
if(progress == null) return; // Not created yet
|
if (progress == null) return; // Not created yet
|
||||||
if(passwordEntry.getText().length() > 0)
|
if (passwordEntry.getText().length() > 0)
|
||||||
strengthMeter.setVisibility(VISIBLE);
|
strengthMeter.setVisibility(VISIBLE);
|
||||||
else strengthMeter.setVisibility(INVISIBLE);
|
else strengthMeter.setVisibility(INVISIBLE);
|
||||||
String nickname = nicknameEntry.getText().toString();
|
String nickname = nicknameEntry.getText().toString();
|
||||||
@@ -192,15 +192,15 @@ OnEditorActionListener {
|
|||||||
boolean passwordsMatch = firstPassword.equals(secondPassword);
|
boolean passwordsMatch = firstPassword.equals(secondPassword);
|
||||||
float strength = strengthEstimator.estimateStrength(firstPassword);
|
float strength = strengthEstimator.estimateStrength(firstPassword);
|
||||||
strengthMeter.setStrength(strength);
|
strengthMeter.setStrength(strength);
|
||||||
if(nicknameLength > MAX_AUTHOR_NAME_LENGTH) {
|
if (nicknameLength > MAX_AUTHOR_NAME_LENGTH) {
|
||||||
feedback.setText(R.string.name_too_long);
|
feedback.setText(R.string.name_too_long);
|
||||||
} else if(firstPassword.length() == 0) {
|
} else if (firstPassword.length() == 0) {
|
||||||
feedback.setText("");
|
feedback.setText("");
|
||||||
} else if(secondPassword.length() == 0 || passwordsMatch) {
|
} else if (secondPassword.length() == 0 || passwordsMatch) {
|
||||||
if(strength < PasswordStrengthEstimator.WEAK)
|
if (strength < PasswordStrengthEstimator.WEAK)
|
||||||
feedback.setText(R.string.password_too_weak);
|
feedback.setText(R.string.password_too_weak);
|
||||||
else feedback.setText("");
|
else feedback.setText("");
|
||||||
} else if(!passwordsMatch) {
|
} else if (!passwordsMatch) {
|
||||||
feedback.setText(R.string.passwords_do_not_match);
|
feedback.setText(R.string.passwords_do_not_match);
|
||||||
} else {
|
} else {
|
||||||
feedback.setText("");
|
feedback.setText("");
|
||||||
@@ -245,7 +245,7 @@ OnEditorActionListener {
|
|||||||
editor.putString("key", StringUtils.toHexString(encrypted));
|
editor.putString("key", StringUtils.toHexString(encrypted));
|
||||||
editor.commit();
|
editor.commit();
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Key storage took " + duration + " ms");
|
LOG.info("Key storage took " + duration + " ms");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,7 +253,7 @@ OnEditorActionListener {
|
|||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
byte[] encrypted = crypto.encryptWithPassword(key.getBytes(), password);
|
byte[] encrypted = crypto.encryptWithPassword(key.getBytes(), password);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Key derivation took " + duration + " ms");
|
LOG.info("Key derivation took " + duration + " ms");
|
||||||
return encrypted;
|
return encrypted;
|
||||||
}
|
}
|
||||||
@@ -266,7 +266,7 @@ OnEditorActionListener {
|
|||||||
LocalAuthor localAuthor = authorFactory.createLocalAuthor(nickname,
|
LocalAuthor localAuthor = authorFactory.createLocalAuthor(nickname,
|
||||||
publicKey, privateKey);
|
publicKey, privateKey);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Identity creation took " + duration + " ms");
|
LOG.info("Identity creation took " + duration + " ms");
|
||||||
return localAuthor;
|
return localAuthor;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public class SplashScreenActivity extends RoboSplashActivity {
|
|||||||
public void onCreate(Bundle state) {
|
public void onCreate(Bundle state) {
|
||||||
super.onCreate(state);
|
super.onCreate(state);
|
||||||
|
|
||||||
if(PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE);
|
if (PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE);
|
||||||
|
|
||||||
LinearLayout layout = new LinearLayout(this);
|
LinearLayout layout = new LinearLayout(this);
|
||||||
layout.setLayoutParams(MATCH_MATCH);
|
layout.setLayoutParams(MATCH_MATCH);
|
||||||
@@ -71,9 +71,9 @@ public class SplashScreenActivity extends RoboSplashActivity {
|
|||||||
@Override
|
@Override
|
||||||
protected void startNextActivity() {
|
protected void startNextActivity() {
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Guice startup took " + duration + " ms");
|
LOG.info("Guice startup took " + duration + " ms");
|
||||||
if(System.currentTimeMillis() >= EXPIRY_DATE) {
|
if (System.currentTimeMillis() >= EXPIRY_DATE) {
|
||||||
LOG.info("Expired");
|
LOG.info("Expired");
|
||||||
startActivity(new Intent(this, ExpiredActivity.class));
|
startActivity(new Intent(this, ExpiredActivity.class));
|
||||||
} else {
|
} else {
|
||||||
@@ -81,7 +81,7 @@ public class SplashScreenActivity extends RoboSplashActivity {
|
|||||||
String hex = prefs.getString("key", null);
|
String hex = prefs.getString("key", null);
|
||||||
Injector i = RoboGuice.getBaseApplicationInjector(getApplication());
|
Injector i = RoboGuice.getBaseApplicationInjector(getApplication());
|
||||||
DatabaseConfig databaseConfig = i.getInstance(DatabaseConfig.class);
|
DatabaseConfig databaseConfig = i.getInstance(DatabaseConfig.class);
|
||||||
if(hex != null && databaseConfig.databaseExists()) {
|
if (hex != null && databaseConfig.databaseExists()) {
|
||||||
startActivity(new Intent(this, DashboardActivity.class));
|
startActivity(new Intent(this, DashboardActivity.class));
|
||||||
} else {
|
} else {
|
||||||
prefs.edit().clear().commit();
|
prefs.edit().clear().commit();
|
||||||
@@ -93,7 +93,7 @@ public class SplashScreenActivity extends RoboSplashActivity {
|
|||||||
|
|
||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
private void enableStrictMode() {
|
private void enableStrictMode() {
|
||||||
if(TESTING && Build.VERSION.SDK_INT >= 9) {
|
if (TESTING && Build.VERSION.SDK_INT >= 9) {
|
||||||
ThreadPolicy.Builder threadPolicy = new ThreadPolicy.Builder();
|
ThreadPolicy.Builder threadPolicy = new ThreadPolicy.Builder();
|
||||||
threadPolicy.detectAll();
|
threadPolicy.detectAll();
|
||||||
threadPolicy.penaltyLog();
|
threadPolicy.penaltyLog();
|
||||||
@@ -106,7 +106,7 @@ public class SplashScreenActivity extends RoboSplashActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void delete(File f) {
|
private void delete(File f) {
|
||||||
if(f.isFile()) f.delete();
|
if (f.isFile()) f.delete();
|
||||||
else if(f.isDirectory()) for(File child : f.listFiles()) delete(child);
|
else if (f.isDirectory()) for (File child : f.listFiles()) delete(child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,12 +153,12 @@ public class TestingActivity extends BriarActivity implements OnClickListener {
|
|||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
if(temp != null) temp.delete();
|
if (temp != null) temp.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
if(view == refresh) refresh();
|
if (view == refresh) refresh();
|
||||||
else if(view == share) share();
|
else if (view == share) share();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refresh() {
|
private void refresh() {
|
||||||
@@ -175,7 +175,7 @@ public class TestingActivity extends BriarActivity implements OnClickListener {
|
|||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(Map<String, String> result) {
|
protected void onPostExecute(Map<String, String> result) {
|
||||||
int pad = LayoutUtils.getPadding(TestingActivity.this);
|
int pad = LayoutUtils.getPadding(TestingActivity.this);
|
||||||
for(Entry<String, String> e : result.entrySet()) {
|
for (Entry<String, String> e : result.entrySet()) {
|
||||||
TextView title = new TextView(TestingActivity.this);
|
TextView title = new TextView(TestingActivity.this);
|
||||||
title.setTextSize(18);
|
title.setTextSize(18);
|
||||||
title.setText(e.getKey());
|
title.setText(e.getKey());
|
||||||
@@ -202,9 +202,9 @@ public class TestingActivity extends BriarActivity implements OnClickListener {
|
|||||||
String manufacturer = Build.MANUFACTURER;
|
String manufacturer = Build.MANUFACTURER;
|
||||||
String model = Build.MODEL;
|
String model = Build.MODEL;
|
||||||
String brand = Build.BRAND;
|
String brand = Build.BRAND;
|
||||||
if(model.startsWith(manufacturer)) deviceType = capitalize(model);
|
if (model.startsWith(manufacturer)) deviceType = capitalize(model);
|
||||||
else deviceType = capitalize(manufacturer) + " " + model;
|
else deviceType = capitalize(manufacturer) + " " + model;
|
||||||
if(!StringUtils.isNullOrEmpty(brand))
|
if (!StringUtils.isNullOrEmpty(brand))
|
||||||
deviceType += " (" + capitalize(brand) + ")";
|
deviceType += " (" + capitalize(brand) + ")";
|
||||||
statusMap.put("Device type:", deviceType);
|
statusMap.put("Device type:", deviceType);
|
||||||
|
|
||||||
@@ -224,7 +224,7 @@ public class TestingActivity extends BriarActivity implements OnClickListener {
|
|||||||
ActivityManager.MemoryInfo mem = new ActivityManager.MemoryInfo();
|
ActivityManager.MemoryInfo mem = new ActivityManager.MemoryInfo();
|
||||||
am.getMemoryInfo(mem);
|
am.getMemoryInfo(mem);
|
||||||
String systemMemory;
|
String systemMemory;
|
||||||
if(Build.VERSION.SDK_INT >= 16) {
|
if (Build.VERSION.SDK_INT >= 16) {
|
||||||
systemMemory = (mem.totalMem / 1024 / 1024) + " MiB total, "
|
systemMemory = (mem.totalMem / 1024 / 1024) + " MiB total, "
|
||||||
+ (mem.availMem / 1024 / 1204) + " MiB free, "
|
+ (mem.availMem / 1024 / 1204) + " MiB free, "
|
||||||
+ (mem.threshold / 1024 / 1024) + " MiB threshold";
|
+ (mem.threshold / 1024 / 1024) + " MiB threshold";
|
||||||
@@ -252,7 +252,7 @@ public class TestingActivity extends BriarActivity implements OnClickListener {
|
|||||||
String internal = (rootTotal / 1024 / 1024) + " MiB total, "
|
String internal = (rootTotal / 1024 / 1024) + " MiB total, "
|
||||||
+ (rootFree / 1024 / 1024) + " MiB free";
|
+ (rootFree / 1024 / 1024) + " MiB free";
|
||||||
statusMap.put("Internal storage:", internal);
|
statusMap.put("Internal storage:", internal);
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
statusMap.put("Internal storage:", "Unknown");
|
statusMap.put("Internal storage:", "Unknown");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,7 +264,7 @@ public class TestingActivity extends BriarActivity implements OnClickListener {
|
|||||||
String external = (sdTotal / 1024 / 1024) + " MiB total, "
|
String external = (sdTotal / 1024 / 1024) + " MiB total, "
|
||||||
+ (sdFree / 1024 / 1024) + " MiB free";
|
+ (sdFree / 1024 / 1024) + " MiB free";
|
||||||
statusMap.put("External storage:", external);
|
statusMap.put("External storage:", external);
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
statusMap.put("External storage:", "Unknown");
|
statusMap.put("External storage:", "Unknown");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,26 +280,26 @@ public class TestingActivity extends BriarActivity implements OnClickListener {
|
|||||||
Method method = clazz.getDeclaredMethod("getMobileDataEnabled");
|
Method method = clazz.getDeclaredMethod("getMobileDataEnabled");
|
||||||
method.setAccessible(true);
|
method.setAccessible(true);
|
||||||
mobileEnabled = (Boolean) method.invoke(cm);
|
mobileEnabled = (Boolean) method.invoke(cm);
|
||||||
} catch(ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
} catch(NoSuchMethodException e) {
|
} catch (NoSuchMethodException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
} catch(IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
} catch(IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
} catch(InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
// Is mobile data connected ?
|
// Is mobile data connected ?
|
||||||
boolean mobileConnected = mobile != null && mobile.isConnected();
|
boolean mobileConnected = mobile != null && mobile.isConnected();
|
||||||
|
|
||||||
String mobileStatus;
|
String mobileStatus;
|
||||||
if(mobileAvailable) mobileStatus = "Available, ";
|
if (mobileAvailable) mobileStatus = "Available, ";
|
||||||
else mobileStatus = "Not available, ";
|
else mobileStatus = "Not available, ";
|
||||||
if(mobileEnabled) mobileStatus += "enabled, ";
|
if (mobileEnabled) mobileStatus += "enabled, ";
|
||||||
else mobileStatus += "not enabled, ";
|
else mobileStatus += "not enabled, ";
|
||||||
if(mobileConnected) mobileStatus += "connected";
|
if (mobileConnected) mobileStatus += "connected";
|
||||||
else mobileStatus += "not connected";
|
else mobileStatus += "not connected";
|
||||||
statusMap.put("Mobile data:", mobileStatus);
|
statusMap.put("Mobile data:", mobileStatus);
|
||||||
|
|
||||||
@@ -314,15 +314,15 @@ public class TestingActivity extends BriarActivity implements OnClickListener {
|
|||||||
boolean wifiConnected = wifi != null && wifi.isConnected();
|
boolean wifiConnected = wifi != null && wifi.isConnected();
|
||||||
|
|
||||||
String wifiStatus;
|
String wifiStatus;
|
||||||
if(wifiAvailable) wifiStatus = "Available, ";
|
if (wifiAvailable) wifiStatus = "Available, ";
|
||||||
else wifiStatus = "Not available, ";
|
else wifiStatus = "Not available, ";
|
||||||
if(wifiEnabled) wifiStatus += "enabled, ";
|
if (wifiEnabled) wifiStatus += "enabled, ";
|
||||||
else wifiStatus += "not enabled, ";
|
else wifiStatus += "not enabled, ";
|
||||||
if(wifiConnected) wifiStatus += "connected";
|
if (wifiConnected) wifiStatus += "connected";
|
||||||
else wifiStatus += "not connected";
|
else wifiStatus += "not connected";
|
||||||
if(wm != null) {
|
if (wm != null) {
|
||||||
WifiInfo wifiInfo = wm.getConnectionInfo();
|
WifiInfo wifiInfo = wm.getConnectionInfo();
|
||||||
if(wifiInfo != null) {
|
if (wifiInfo != null) {
|
||||||
int ip = wifiInfo.getIpAddress(); // Nice API, Google
|
int ip = wifiInfo.getIpAddress(); // Nice API, Google
|
||||||
int ip1 = ip & 0xFF;
|
int ip1 = ip & 0xFF;
|
||||||
int ip2 = (ip >> 8) & 0xFF;
|
int ip2 = (ip >> 8) & 0xFF;
|
||||||
@@ -342,11 +342,11 @@ public class TestingActivity extends BriarActivity implements OnClickListener {
|
|||||||
return BluetoothAdapter.getDefaultAdapter();
|
return BluetoothAdapter.getDefaultAdapter();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch(InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.warning("Interrupted while getting BluetoothAdapter");
|
LOG.warning("Interrupted while getting BluetoothAdapter");
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
} catch(ExecutionException e) {
|
} catch (ExecutionException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
boolean btAvailable = bt != null;
|
boolean btAvailable = bt != null;
|
||||||
// Is Bluetooth enabled?
|
// Is Bluetooth enabled?
|
||||||
@@ -361,26 +361,26 @@ public class TestingActivity extends BriarActivity implements OnClickListener {
|
|||||||
bt.getScanMode() == SCAN_MODE_CONNECTABLE_DISCOVERABLE;
|
bt.getScanMode() == SCAN_MODE_CONNECTABLE_DISCOVERABLE;
|
||||||
|
|
||||||
String btStatus;
|
String btStatus;
|
||||||
if(btAvailable) btStatus = "Available, ";
|
if (btAvailable) btStatus = "Available, ";
|
||||||
else btStatus = "Not available, ";
|
else btStatus = "Not available, ";
|
||||||
if(btEnabled) btStatus += "enabled, ";
|
if (btEnabled) btStatus += "enabled, ";
|
||||||
else btStatus += "not enabled, ";
|
else btStatus += "not enabled, ";
|
||||||
if(btConnectable) btStatus += "connectable, ";
|
if (btConnectable) btStatus += "connectable, ";
|
||||||
else btStatus += "not connectable, ";
|
else btStatus += "not connectable, ";
|
||||||
if(btDiscoverable) btStatus += "discoverable";
|
if (btDiscoverable) btStatus += "discoverable";
|
||||||
else btStatus += "not discoverable";
|
else btStatus += "not discoverable";
|
||||||
if(bt != null) btStatus += "\nAddress: " + bt.getAddress();
|
if (bt != null) btStatus += "\nAddress: " + bt.getAddress();
|
||||||
statusMap.put("Bluetooth:", btStatus);
|
statusMap.put("Bluetooth:", btStatus);
|
||||||
|
|
||||||
Map<TransportId, TransportProperties> props = Collections.emptyMap();
|
Map<TransportId, TransportProperties> props = Collections.emptyMap();
|
||||||
try {
|
try {
|
||||||
lifecycleManager.waitForDatabase();
|
lifecycleManager.waitForDatabase();
|
||||||
props = db.getLocalProperties();
|
props = db.getLocalProperties();
|
||||||
} catch(InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.info("Interrupted while waiting for database");
|
LOG.info("Interrupted while waiting for database");
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
Plugin torPlugin = pluginManager.getPlugin(new TransportId("tor"));
|
Plugin torPlugin = pluginManager.getPlugin(new TransportId("tor"));
|
||||||
@@ -388,12 +388,12 @@ public class TestingActivity extends BriarActivity implements OnClickListener {
|
|||||||
boolean torPluginRunning = torPlugin != null && torPlugin.isRunning();
|
boolean torPluginRunning = torPlugin != null && torPlugin.isRunning();
|
||||||
|
|
||||||
String torPluginStatus;
|
String torPluginStatus;
|
||||||
if(torPluginEnabled) torPluginStatus = "Enabled, ";
|
if (torPluginEnabled) torPluginStatus = "Enabled, ";
|
||||||
else torPluginStatus = "Not enabled, ";
|
else torPluginStatus = "Not enabled, ";
|
||||||
if(torPluginRunning) torPluginStatus += "running";
|
if (torPluginRunning) torPluginStatus += "running";
|
||||||
else torPluginStatus += "not running";
|
else torPluginStatus += "not running";
|
||||||
TransportProperties torProps = props.get(new TransportId("tor"));
|
TransportProperties torProps = props.get(new TransportId("tor"));
|
||||||
if(torProps != null)
|
if (torProps != null)
|
||||||
torPluginStatus += "\nAddress: " + torProps.get("onion");
|
torPluginStatus += "\nAddress: " + torProps.get("onion");
|
||||||
statusMap.put("Tor plugin:", torPluginStatus);
|
statusMap.put("Tor plugin:", torPluginStatus);
|
||||||
|
|
||||||
@@ -402,12 +402,12 @@ public class TestingActivity extends BriarActivity implements OnClickListener {
|
|||||||
boolean lanPluginRunning = lanPlugin != null && lanPlugin.isRunning();
|
boolean lanPluginRunning = lanPlugin != null && lanPlugin.isRunning();
|
||||||
|
|
||||||
String lanPluginStatus;
|
String lanPluginStatus;
|
||||||
if(lanPluginEnabled) lanPluginStatus = "Enabled, ";
|
if (lanPluginEnabled) lanPluginStatus = "Enabled, ";
|
||||||
else lanPluginStatus = "Not enabled, ";
|
else lanPluginStatus = "Not enabled, ";
|
||||||
if(lanPluginRunning) lanPluginStatus += "running";
|
if (lanPluginRunning) lanPluginStatus += "running";
|
||||||
else lanPluginStatus += "not running";
|
else lanPluginStatus += "not running";
|
||||||
TransportProperties lanProps = props.get(new TransportId("lan"));
|
TransportProperties lanProps = props.get(new TransportId("lan"));
|
||||||
if(lanProps != null)
|
if (lanProps != null)
|
||||||
lanPluginStatus += "\nAddress: " + lanProps.get("address");
|
lanPluginStatus += "\nAddress: " + lanProps.get("address");
|
||||||
statusMap.put("LAN plugin:", lanPluginStatus);
|
statusMap.put("LAN plugin:", lanPluginStatus);
|
||||||
|
|
||||||
@@ -416,12 +416,12 @@ public class TestingActivity extends BriarActivity implements OnClickListener {
|
|||||||
boolean btPluginRunning = btPlugin != null && btPlugin.isRunning();
|
boolean btPluginRunning = btPlugin != null && btPlugin.isRunning();
|
||||||
|
|
||||||
String btPluginStatus;
|
String btPluginStatus;
|
||||||
if(btPluginEnabled) btPluginStatus = "Enabled, ";
|
if (btPluginEnabled) btPluginStatus = "Enabled, ";
|
||||||
else btPluginStatus = "Not enabled, ";
|
else btPluginStatus = "Not enabled, ";
|
||||||
if(btPluginRunning) btPluginStatus += "running";
|
if (btPluginRunning) btPluginStatus += "running";
|
||||||
else btPluginStatus += "not running";
|
else btPluginStatus += "not running";
|
||||||
TransportProperties btProps = props.get(new TransportId("bt"));
|
TransportProperties btProps = props.get(new TransportId("bt"));
|
||||||
if(btProps != null)
|
if (btProps != null)
|
||||||
btPluginStatus += "\nAddress: " + btProps.get("address");
|
btPluginStatus += "\nAddress: " + btProps.get("address");
|
||||||
statusMap.put("Bluetooth plugin:", btPluginStatus);
|
statusMap.put("Bluetooth plugin:", btPluginStatus);
|
||||||
|
|
||||||
@@ -432,16 +432,16 @@ public class TestingActivity extends BriarActivity implements OnClickListener {
|
|||||||
Pattern pattern = Pattern.compile(".*\\( *" + pid + "\\).*");
|
Pattern pattern = Pattern.compile(".*\\( *" + pid + "\\).*");
|
||||||
Process process = runtime.exec("logcat -d -v time *:I");
|
Process process = runtime.exec("logcat -d -v time *:I");
|
||||||
Scanner scanner = new Scanner(process.getInputStream());
|
Scanner scanner = new Scanner(process.getInputStream());
|
||||||
while(scanner.hasNextLine()) {
|
while (scanner.hasNextLine()) {
|
||||||
String line = scanner.nextLine();
|
String line = scanner.nextLine();
|
||||||
if(pattern.matcher(line).matches()) {
|
if (pattern.matcher(line).matches()) {
|
||||||
log.append(line);
|
log.append(line);
|
||||||
log.append('\n');
|
log.append('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scanner.close();
|
scanner.close();
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
statusMap.put("Debugging log:", log.toString());
|
statusMap.put("Debugging log:", log.toString());
|
||||||
|
|
||||||
@@ -449,9 +449,9 @@ public class TestingActivity extends BriarActivity implements OnClickListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String capitalize(String s) {
|
private String capitalize(String s) {
|
||||||
if(StringUtils.isNullOrEmpty(s)) return s;
|
if (StringUtils.isNullOrEmpty(s)) return s;
|
||||||
char first = s.charAt(0);
|
char first = s.charAt(0);
|
||||||
if(Character.isUpperCase(first)) return s;
|
if (Character.isUpperCase(first)) return s;
|
||||||
return Character.toUpperCase(first) + s.substring(1);
|
return Character.toUpperCase(first) + s.substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,10 +468,10 @@ public class TestingActivity extends BriarActivity implements OnClickListener {
|
|||||||
try {
|
try {
|
||||||
File shared = Environment.getExternalStorageDirectory();
|
File shared = Environment.getExternalStorageDirectory();
|
||||||
temp = File.createTempFile("debug", ".txt", shared);
|
temp = File.createTempFile("debug", ".txt", shared);
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Writing to " + temp.getPath());
|
LOG.info("Writing to " + temp.getPath());
|
||||||
PrintStream p = new PrintStream(new FileOutputStream(temp));
|
PrintStream p = new PrintStream(new FileOutputStream(temp));
|
||||||
for(Entry<String, String> e : result.entrySet()) {
|
for (Entry<String, String> e : result.entrySet()) {
|
||||||
p.println(e.getKey());
|
p.println(e.getKey());
|
||||||
p.println(e.getValue());
|
p.println(e.getValue());
|
||||||
p.println();
|
p.println();
|
||||||
@@ -479,8 +479,8 @@ public class TestingActivity extends BriarActivity implements OnClickListener {
|
|||||||
p.flush();
|
p.flush();
|
||||||
p.close();
|
p.close();
|
||||||
sendEmail(Uri.fromFile(temp));
|
sendEmail(Uri.fromFile(temp));
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,22 +138,22 @@ EventListener {
|
|||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
for(Contact c : db.getContacts()) {
|
for (Contact c : db.getContacts()) {
|
||||||
try {
|
try {
|
||||||
GroupId inbox = db.getInboxGroupId(c.getId());
|
GroupId inbox = db.getInboxGroupId(c.getId());
|
||||||
Collection<MessageHeader> headers =
|
Collection<MessageHeader> headers =
|
||||||
db.getInboxMessageHeaders(c.getId());
|
db.getInboxMessageHeaders(c.getId());
|
||||||
displayContact(c, inbox, headers);
|
displayContact(c, inbox, headers);
|
||||||
} catch(NoSuchContactException e) {
|
} catch (NoSuchContactException e) {
|
||||||
// Continue
|
// Continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Full load took " + duration + " ms");
|
LOG.info("Full load took " + duration + " ms");
|
||||||
hideProgressBar();
|
hideProgressBar();
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,7 +181,7 @@ EventListener {
|
|||||||
boolean connected = connectionRegistry.isConnected(c.getId());
|
boolean connected = connectionRegistry.isConnected(c.getId());
|
||||||
// Remove the old item, if any
|
// Remove the old item, if any
|
||||||
ContactListItem item = findItem(c.getId());
|
ContactListItem item = findItem(c.getId());
|
||||||
if(item != null) adapter.remove(item);
|
if (item != null) adapter.remove(item);
|
||||||
// Add a new item
|
// Add a new item
|
||||||
adapter.add(new ContactListItem(c, connected, inbox, headers));
|
adapter.add(new ContactListItem(c, connected, inbox, headers));
|
||||||
adapter.sort(ContactListItemComparator.INSTANCE);
|
adapter.sort(ContactListItemComparator.INSTANCE);
|
||||||
@@ -193,7 +193,7 @@ EventListener {
|
|||||||
private void hideProgressBar() {
|
private void hideProgressBar() {
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
if(adapter.isEmpty()) empty.setVisibility(VISIBLE);
|
if (adapter.isEmpty()) empty.setVisibility(VISIBLE);
|
||||||
else list.setVisibility(VISIBLE);
|
else list.setVisibility(VISIBLE);
|
||||||
loading.setVisibility(GONE);
|
loading.setVisibility(GONE);
|
||||||
}
|
}
|
||||||
@@ -202,9 +202,9 @@ EventListener {
|
|||||||
|
|
||||||
private ContactListItem findItem(ContactId c) {
|
private ContactListItem findItem(ContactId c) {
|
||||||
int count = adapter.getCount();
|
int count = adapter.getCount();
|
||||||
for(int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
ContactListItem item = adapter.getItem(i);
|
ContactListItem item = adapter.getItem(i);
|
||||||
if(item.getContact().getId().equals(c)) return item;
|
if (item.getContact().getId().equals(c)) return item;
|
||||||
}
|
}
|
||||||
return null; // Not found
|
return null; // Not found
|
||||||
}
|
}
|
||||||
@@ -243,7 +243,7 @@ EventListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onContextItemSelected(MenuItem menuItem) {
|
public boolean onContextItemSelected(MenuItem menuItem) {
|
||||||
if(menuItem.getItemId() == MENU_ITEM_DELETE) {
|
if (menuItem.getItemId() == MENU_ITEM_DELETE) {
|
||||||
ContextMenuInfo info = menuItem.getMenuInfo();
|
ContextMenuInfo info = menuItem.getMenuInfo();
|
||||||
int position = ((AdapterContextMenuInfo) info).position;
|
int position = ((AdapterContextMenuInfo) info).position;
|
||||||
ContactListItem item = adapter.getItem(position);
|
ContactListItem item = adapter.getItem(position);
|
||||||
@@ -259,8 +259,8 @@ EventListener {
|
|||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
db.removeContact(c);
|
db.removeContact(c);
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -268,21 +268,21 @@ EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if(e instanceof ContactAddedEvent) {
|
if (e instanceof ContactAddedEvent) {
|
||||||
loadContacts();
|
loadContacts();
|
||||||
} else if(e instanceof ContactConnectedEvent) {
|
} else if (e instanceof ContactConnectedEvent) {
|
||||||
setConnected(((ContactConnectedEvent) e).getContactId(), true);
|
setConnected(((ContactConnectedEvent) e).getContactId(), true);
|
||||||
} else if(e instanceof ContactDisconnectedEvent) {
|
} else if (e instanceof ContactDisconnectedEvent) {
|
||||||
setConnected(((ContactDisconnectedEvent) e).getContactId(), false);
|
setConnected(((ContactDisconnectedEvent) e).getContactId(), false);
|
||||||
} else if(e instanceof ContactRemovedEvent) {
|
} else if (e instanceof ContactRemovedEvent) {
|
||||||
LOG.info("Contact removed");
|
LOG.info("Contact removed");
|
||||||
removeItem(((ContactRemovedEvent) e).getContactId());
|
removeItem(((ContactRemovedEvent) e).getContactId());
|
||||||
} else if(e instanceof MessageAddedEvent) {
|
} else if (e instanceof MessageAddedEvent) {
|
||||||
LOG.info("Message added, reloading");
|
LOG.info("Message added, reloading");
|
||||||
ContactId source = ((MessageAddedEvent) e).getContactId();
|
ContactId source = ((MessageAddedEvent) e).getContactId();
|
||||||
if(source == null) loadContacts();
|
if (source == null) loadContacts();
|
||||||
else reloadContact(source);
|
else reloadContact(source);
|
||||||
} else if(e instanceof MessageExpiredEvent) {
|
} else if (e instanceof MessageExpiredEvent) {
|
||||||
LOG.info("Message expired, reloading");
|
LOG.info("Message expired, reloading");
|
||||||
loadContacts();
|
loadContacts();
|
||||||
}
|
}
|
||||||
@@ -296,13 +296,13 @@ EventListener {
|
|||||||
Collection<MessageHeader> headers =
|
Collection<MessageHeader> headers =
|
||||||
db.getInboxMessageHeaders(c);
|
db.getInboxMessageHeaders(c);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Partial load took " + duration + " ms");
|
LOG.info("Partial load took " + duration + " ms");
|
||||||
updateItem(c, headers);
|
updateItem(c, headers);
|
||||||
} catch(NoSuchContactException e) {
|
} catch (NoSuchContactException e) {
|
||||||
removeItem(c);
|
removeItem(c);
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -314,7 +314,7 @@ EventListener {
|
|||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
ContactListItem item = findItem(c);
|
ContactListItem item = findItem(c);
|
||||||
if(item != null) {
|
if (item != null) {
|
||||||
item.setHeaders(headers);
|
item.setHeaders(headers);
|
||||||
adapter.notifyDataSetChanged();
|
adapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
@@ -326,10 +326,10 @@ EventListener {
|
|||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
ContactListItem item = findItem(c);
|
ContactListItem item = findItem(c);
|
||||||
if(item != null) {
|
if (item != null) {
|
||||||
adapter.remove(item);
|
adapter.remove(item);
|
||||||
adapter.notifyDataSetChanged();
|
adapter.notifyDataSetChanged();
|
||||||
if(adapter.isEmpty()) {
|
if (adapter.isEmpty()) {
|
||||||
empty.setVisibility(VISIBLE);
|
empty.setVisibility(VISIBLE);
|
||||||
list.setVisibility(GONE);
|
list.setVisibility(GONE);
|
||||||
}
|
}
|
||||||
@@ -342,7 +342,7 @@ EventListener {
|
|||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
ContactListItem item = findItem(c);
|
ContactListItem item = findItem(c);
|
||||||
if(item != null) {
|
if (item != null) {
|
||||||
item.setConnected(connected);
|
item.setConnected(connected);
|
||||||
adapter.notifyDataSetChanged();
|
adapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,12 +40,12 @@ class ContactListAdapter extends ArrayAdapter<ContactListItem> {
|
|||||||
layout.setOrientation(HORIZONTAL);
|
layout.setOrientation(HORIZONTAL);
|
||||||
layout.setGravity(CENTER_VERTICAL);
|
layout.setGravity(CENTER_VERTICAL);
|
||||||
int unread = item.getUnreadCount();
|
int unread = item.getUnreadCount();
|
||||||
if(unread > 0)
|
if (unread > 0)
|
||||||
layout.setBackgroundColor(res.getColor(R.color.unread_background));
|
layout.setBackgroundColor(res.getColor(R.color.unread_background));
|
||||||
|
|
||||||
ImageView bulb = new ImageView(ctx);
|
ImageView bulb = new ImageView(ctx);
|
||||||
bulb.setPadding(pad, pad, pad, pad);
|
bulb.setPadding(pad, pad, pad, pad);
|
||||||
if(item.isConnected())
|
if (item.isConnected())
|
||||||
bulb.setImageResource(R.drawable.contact_connected);
|
bulb.setImageResource(R.drawable.contact_connected);
|
||||||
else bulb.setImageResource(R.drawable.contact_disconnected);
|
else bulb.setImageResource(R.drawable.contact_disconnected);
|
||||||
layout.addView(bulb);
|
layout.addView(bulb);
|
||||||
@@ -57,11 +57,11 @@ class ContactListAdapter extends ArrayAdapter<ContactListItem> {
|
|||||||
name.setEllipsize(END);
|
name.setEllipsize(END);
|
||||||
name.setPadding(0, pad, pad, pad);
|
name.setPadding(0, pad, pad, pad);
|
||||||
String contactName = item.getContact().getAuthor().getName();
|
String contactName = item.getContact().getAuthor().getName();
|
||||||
if(unread > 0) name.setText(contactName + " (" + unread + ")");
|
if (unread > 0) name.setText(contactName + " (" + unread + ")");
|
||||||
else name.setText(contactName);
|
else name.setText(contactName);
|
||||||
layout.addView(name);
|
layout.addView(name);
|
||||||
|
|
||||||
if(item.isEmpty()) {
|
if (item.isEmpty()) {
|
||||||
TextView noMessages = new TextView(ctx);
|
TextView noMessages = new TextView(ctx);
|
||||||
noMessages.setPadding(pad, pad, pad, pad);
|
noMessages.setPadding(pad, pad, pad, pad);
|
||||||
noMessages.setTextColor(res.getColor(R.color.no_private_messages));
|
noMessages.setTextColor(res.getColor(R.color.no_private_messages));
|
||||||
|
|||||||
@@ -27,10 +27,10 @@ class ContactListItem {
|
|||||||
empty = headers.isEmpty();
|
empty = headers.isEmpty();
|
||||||
timestamp = 0;
|
timestamp = 0;
|
||||||
unread = 0;
|
unread = 0;
|
||||||
if(!empty) {
|
if (!empty) {
|
||||||
for(MessageHeader h : headers) {
|
for (MessageHeader h : headers) {
|
||||||
if(h.getTimestamp() > timestamp) timestamp = h.getTimestamp();
|
if (h.getTimestamp() > timestamp) timestamp = h.getTimestamp();
|
||||||
if(!h.isRead()) unread++;
|
if (!h.isRead()) unread++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ implements EventListener, OnClickListener, OnItemClickListener {
|
|||||||
|
|
||||||
Intent i = getIntent();
|
Intent i = getIntent();
|
||||||
int id = i.getIntExtra("briar.CONTACT_ID", -1);
|
int id = i.getIntExtra("briar.CONTACT_ID", -1);
|
||||||
if(id == -1) throw new IllegalStateException();
|
if (id == -1) throw new IllegalStateException();
|
||||||
contactId = new ContactId(id);
|
contactId = new ContactId(id);
|
||||||
|
|
||||||
Intent data = new Intent();
|
Intent data = new Intent();
|
||||||
@@ -206,17 +206,17 @@ implements EventListener, OnClickListener, OnItemClickListener {
|
|||||||
groupId = db.getInboxGroupId(contactId);
|
groupId = db.getInboxGroupId(contactId);
|
||||||
group = db.getGroup(groupId);
|
group = db.getGroup(groupId);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
LOG.info("Loading contact and group took "
|
LOG.info("Loading contact and group took "
|
||||||
+ duration + " ms");
|
+ duration + " ms");
|
||||||
}
|
}
|
||||||
displayContactName();
|
displayContactName();
|
||||||
} catch(NoSuchContactException e) {
|
} catch (NoSuchContactException e) {
|
||||||
finishOnUiThread();
|
finishOnUiThread();
|
||||||
} catch(NoSuchSubscriptionException e) {
|
} catch (NoSuchSubscriptionException e) {
|
||||||
finishOnUiThread();
|
finishOnUiThread();
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -239,13 +239,13 @@ implements EventListener, OnClickListener, OnItemClickListener {
|
|||||||
Collection<MessageHeader> headers =
|
Collection<MessageHeader> headers =
|
||||||
db.getInboxMessageHeaders(contactId);
|
db.getInboxMessageHeaders(contactId);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Loading headers took " + duration + " ms");
|
LOG.info("Loading headers took " + duration + " ms");
|
||||||
displayHeaders(headers);
|
displayHeaders(headers);
|
||||||
} catch(NoSuchContactException e) {
|
} catch (NoSuchContactException e) {
|
||||||
finishOnUiThread();
|
finishOnUiThread();
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -259,16 +259,16 @@ implements EventListener, OnClickListener, OnItemClickListener {
|
|||||||
setTitle(contactName);
|
setTitle(contactName);
|
||||||
sendButton.setEnabled(true);
|
sendButton.setEnabled(true);
|
||||||
adapter.clear();
|
adapter.clear();
|
||||||
if(headers.isEmpty()) {
|
if (headers.isEmpty()) {
|
||||||
empty.setVisibility(VISIBLE);
|
empty.setVisibility(VISIBLE);
|
||||||
list.setVisibility(GONE);
|
list.setVisibility(GONE);
|
||||||
} else {
|
} else {
|
||||||
empty.setVisibility(GONE);
|
empty.setVisibility(GONE);
|
||||||
list.setVisibility(VISIBLE);
|
list.setVisibility(VISIBLE);
|
||||||
for(MessageHeader h : headers) {
|
for (MessageHeader h : headers) {
|
||||||
ConversationItem item = new ConversationItem(h);
|
ConversationItem item = new ConversationItem(h);
|
||||||
byte[] body = bodyCache.get(h.getId());
|
byte[] body = bodyCache.get(h.getId());
|
||||||
if(body == null) loadMessageBody(h);
|
if (body == null) loadMessageBody(h);
|
||||||
else item.setBody(body);
|
else item.setBody(body);
|
||||||
adapter.add(item);
|
adapter.add(item);
|
||||||
}
|
}
|
||||||
@@ -288,13 +288,13 @@ implements EventListener, OnClickListener, OnItemClickListener {
|
|||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
byte[] body = db.getMessageBody(h.getId());
|
byte[] body = db.getMessageBody(h.getId());
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Loading message took " + duration + " ms");
|
LOG.info("Loading message took " + duration + " ms");
|
||||||
displayMessageBody(h.getId(), body);
|
displayMessageBody(h.getId(), body);
|
||||||
} catch(NoSuchMessageException e) {
|
} catch (NoSuchMessageException e) {
|
||||||
// The item will be removed when we get the event
|
// The item will be removed when we get the event
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -306,9 +306,9 @@ implements EventListener, OnClickListener, OnItemClickListener {
|
|||||||
public void run() {
|
public void run() {
|
||||||
bodyCache.put(m, body);
|
bodyCache.put(m, body);
|
||||||
int count = adapter.getCount();
|
int count = adapter.getCount();
|
||||||
for(int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
ConversationItem item = adapter.getItem(i);
|
ConversationItem item = adapter.getItem(i);
|
||||||
if(item.getHeader().getId().equals(m)) {
|
if (item.getHeader().getId().equals(m)) {
|
||||||
item.setBody(body);
|
item.setBody(body);
|
||||||
adapter.notifyDataSetChanged();
|
adapter.notifyDataSetChanged();
|
||||||
// Scroll to the bottom
|
// Scroll to the bottom
|
||||||
@@ -323,9 +323,9 @@ implements EventListener, OnClickListener, OnItemClickListener {
|
|||||||
@Override
|
@Override
|
||||||
protected void onActivityResult(int request, int result, Intent data) {
|
protected void onActivityResult(int request, int result, Intent data) {
|
||||||
super.onActivityResult(request, result, data);
|
super.onActivityResult(request, result, data);
|
||||||
if(request == REQUEST_READ && result == RESULT_PREV_NEXT) {
|
if (request == REQUEST_READ && result == RESULT_PREV_NEXT) {
|
||||||
int position = data.getIntExtra("briar.POSITION", -1);
|
int position = data.getIntExtra("briar.POSITION", -1);
|
||||||
if(position >= 0 && position < adapter.getCount())
|
if (position >= 0 && position < adapter.getCount())
|
||||||
displayMessage(position);
|
displayMessage(position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -334,19 +334,19 @@ implements EventListener, OnClickListener, OnItemClickListener {
|
|||||||
public void onPause() {
|
public void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
eventBus.removeListener(this);
|
eventBus.removeListener(this);
|
||||||
if(isFinishing()) markMessagesRead();
|
if (isFinishing()) markMessagesRead();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markMessagesRead() {
|
private void markMessagesRead() {
|
||||||
notificationManager.clearPrivateMessageNotification(contactId);
|
notificationManager.clearPrivateMessageNotification(contactId);
|
||||||
List<MessageId> unread = new ArrayList<MessageId>();
|
List<MessageId> unread = new ArrayList<MessageId>();
|
||||||
int count = adapter.getCount();
|
int count = adapter.getCount();
|
||||||
for(int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
MessageHeader h = adapter.getItem(i).getHeader();
|
MessageHeader h = adapter.getItem(i).getHeader();
|
||||||
if(!h.isRead()) unread.add(h.getId());
|
if (!h.isRead()) unread.add(h.getId());
|
||||||
}
|
}
|
||||||
if(unread.isEmpty()) return;
|
if (unread.isEmpty()) return;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Marking " + unread.size() + " messages read");
|
LOG.info("Marking " + unread.size() + " messages read");
|
||||||
markMessagesRead(Collections.unmodifiableList(unread));
|
markMessagesRead(Collections.unmodifiableList(unread));
|
||||||
}
|
}
|
||||||
@@ -356,12 +356,12 @@ implements EventListener, OnClickListener, OnItemClickListener {
|
|||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
for(MessageId m : unread) db.setReadFlag(m, true);
|
for (MessageId m : unread) db.setReadFlag(m, true);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Marking read took " + duration + " ms");
|
LOG.info("Marking read took " + duration + " ms");
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -369,24 +369,24 @@ implements EventListener, OnClickListener, OnItemClickListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if(e instanceof ContactRemovedEvent) {
|
if (e instanceof ContactRemovedEvent) {
|
||||||
ContactRemovedEvent c = (ContactRemovedEvent) e;
|
ContactRemovedEvent c = (ContactRemovedEvent) e;
|
||||||
if(c.getContactId().equals(contactId)) {
|
if (c.getContactId().equals(contactId)) {
|
||||||
LOG.info("Contact removed");
|
LOG.info("Contact removed");
|
||||||
finishOnUiThread();
|
finishOnUiThread();
|
||||||
}
|
}
|
||||||
} else if(e instanceof MessageAddedEvent) {
|
} else if (e instanceof MessageAddedEvent) {
|
||||||
GroupId g = ((MessageAddedEvent) e).getGroup().getId();
|
GroupId g = ((MessageAddedEvent) e).getGroup().getId();
|
||||||
if(g.equals(groupId)) {
|
if (g.equals(groupId)) {
|
||||||
LOG.info("Message added, reloading");
|
LOG.info("Message added, reloading");
|
||||||
loadHeaders();
|
loadHeaders();
|
||||||
}
|
}
|
||||||
} else if(e instanceof MessageExpiredEvent) {
|
} else if (e instanceof MessageExpiredEvent) {
|
||||||
LOG.info("Message expired, reloading");
|
LOG.info("Message expired, reloading");
|
||||||
loadHeaders();
|
loadHeaders();
|
||||||
} else if(e instanceof MessagesAckedEvent) {
|
} else if (e instanceof MessagesAckedEvent) {
|
||||||
MessagesAckedEvent m = (MessagesAckedEvent) e;
|
MessagesAckedEvent m = (MessagesAckedEvent) e;
|
||||||
if(m.getContactId().equals(contactId)) {
|
if (m.getContactId().equals(contactId)) {
|
||||||
LOG.info("Messages acked");
|
LOG.info("Messages acked");
|
||||||
markMessagesDelivered(m.getMessageIds());
|
markMessagesDelivered(m.getMessageIds());
|
||||||
}
|
}
|
||||||
@@ -399,21 +399,21 @@ implements EventListener, OnClickListener, OnItemClickListener {
|
|||||||
Set<MessageId> ackedSet = new HashSet<MessageId>(acked);
|
Set<MessageId> ackedSet = new HashSet<MessageId>(acked);
|
||||||
boolean changed = false;
|
boolean changed = false;
|
||||||
int count = adapter.getCount();
|
int count = adapter.getCount();
|
||||||
for(int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
ConversationItem item = adapter.getItem(i);
|
ConversationItem item = adapter.getItem(i);
|
||||||
if(ackedSet.contains(item.getHeader().getId())) {
|
if (ackedSet.contains(item.getHeader().getId())) {
|
||||||
item.setDelivered(true);
|
item.setDelivered(true);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(changed) adapter.notifyDataSetChanged();
|
if (changed) adapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
String message = content.getText().toString();
|
String message = content.getText().toString();
|
||||||
if(message.equals("")) return;
|
if (message.equals("")) return;
|
||||||
long timestamp = System.currentTimeMillis();
|
long timestamp = System.currentTimeMillis();
|
||||||
timestamp = Math.max(timestamp, getMinTimestampForNewMessage());
|
timestamp = Math.max(timestamp, getMinTimestampForNewMessage());
|
||||||
createMessage(StringUtils.toUtf8(message), timestamp);
|
createMessage(StringUtils.toUtf8(message), timestamp);
|
||||||
@@ -426,9 +426,9 @@ implements EventListener, OnClickListener, OnItemClickListener {
|
|||||||
// Don't use an earlier timestamp than the newest message
|
// Don't use an earlier timestamp than the newest message
|
||||||
long timestamp = 0;
|
long timestamp = 0;
|
||||||
int count = adapter.getCount();
|
int count = adapter.getCount();
|
||||||
for(int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
long t = adapter.getItem(i).getHeader().getTimestamp();
|
long t = adapter.getItem(i).getHeader().getTimestamp();
|
||||||
if(t > timestamp) timestamp = t;
|
if (t > timestamp) timestamp = t;
|
||||||
}
|
}
|
||||||
return timestamp + 1;
|
return timestamp + 1;
|
||||||
}
|
}
|
||||||
@@ -440,9 +440,9 @@ implements EventListener, OnClickListener, OnItemClickListener {
|
|||||||
Message m = messageFactory.createAnonymousMessage(null,
|
Message m = messageFactory.createAnonymousMessage(null,
|
||||||
group, "text/plain", timestamp, body);
|
group, "text/plain", timestamp, body);
|
||||||
storeMessage(m);
|
storeMessage(m);
|
||||||
} catch(GeneralSecurityException e) {
|
} catch (GeneralSecurityException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -456,10 +456,10 @@ implements EventListener, OnClickListener, OnItemClickListener {
|
|||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
db.addLocalMessage(m);
|
db.addLocalMessage(m);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Storing message took " + duration + " ms");
|
LOG.info("Storing message took " + duration + " ms");
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,17 +45,17 @@ class ConversationAdapter extends ArrayAdapter<ConversationItem> {
|
|||||||
|
|
||||||
LinearLayout layout = new LinearLayout(ctx);
|
LinearLayout layout = new LinearLayout(ctx);
|
||||||
layout.setOrientation(VERTICAL);
|
layout.setOrientation(VERTICAL);
|
||||||
if(header.isLocal()) layout.setPadding(3 * pad, 0, 0, 0);
|
if (header.isLocal()) layout.setPadding(3 * pad, 0, 0, 0);
|
||||||
else layout.setPadding(0, 0, 3 * pad, 0);
|
else layout.setPadding(0, 0, 3 * pad, 0);
|
||||||
|
|
||||||
int background = res.getColor(R.color.private_message_background);
|
int background = res.getColor(R.color.private_message_background);
|
||||||
|
|
||||||
View content;
|
View content;
|
||||||
if(item.getBody() == null) {
|
if (item.getBody() == null) {
|
||||||
TextView ellipsis = new TextView(ctx);
|
TextView ellipsis = new TextView(ctx);
|
||||||
ellipsis.setText("\u2026");
|
ellipsis.setText("\u2026");
|
||||||
content = ellipsis;
|
content = ellipsis;
|
||||||
} else if(header.getContentType().equals("text/plain")) {
|
} else if (header.getContentType().equals("text/plain")) {
|
||||||
TextView text = new TextView(ctx);
|
TextView text = new TextView(ctx);
|
||||||
text.setText(StringUtils.fromUtf8(item.getBody()));
|
text.setText(StringUtils.fromUtf8(item.getBody()));
|
||||||
content = text;
|
content = text;
|
||||||
@@ -69,7 +69,7 @@ class ConversationAdapter extends ArrayAdapter<ConversationItem> {
|
|||||||
content.setPadding(pad, pad, pad, 0);
|
content.setPadding(pad, pad, pad, 0);
|
||||||
layout.addView(content);
|
layout.addView(content);
|
||||||
|
|
||||||
if(header.isLocal()) {
|
if (header.isLocal()) {
|
||||||
LinearLayout footer = new LinearLayout(ctx);
|
LinearLayout footer = new LinearLayout(ctx);
|
||||||
footer.setLayoutParams(MATCH_WRAP);
|
footer.setLayoutParams(MATCH_WRAP);
|
||||||
footer.setOrientation(HORIZONTAL);
|
footer.setOrientation(HORIZONTAL);
|
||||||
@@ -82,7 +82,7 @@ class ConversationAdapter extends ArrayAdapter<ConversationItem> {
|
|||||||
ImageView delivered = new ImageView(ctx);
|
ImageView delivered = new ImageView(ctx);
|
||||||
delivered.setPadding(0, 0, pad, 0);
|
delivered.setPadding(0, 0, pad, 0);
|
||||||
delivered.setImageResource(R.drawable.message_delivered);
|
delivered.setImageResource(R.drawable.message_delivered);
|
||||||
if(!item.isDelivered()) delivered.setVisibility(INVISIBLE);
|
if (!item.isDelivered()) delivered.setVisibility(INVISIBLE);
|
||||||
footer.addView(delivered);
|
footer.addView(delivered);
|
||||||
|
|
||||||
TextView date = new TextView(ctx);
|
TextView date = new TextView(ctx);
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ class ConversationItemComparator implements Comparator<ConversationItem> {
|
|||||||
// The oldest message comes first
|
// The oldest message comes first
|
||||||
long aTime = a.getHeader().getTimestamp();
|
long aTime = a.getHeader().getTimestamp();
|
||||||
long bTime = b.getHeader().getTimestamp();
|
long bTime = b.getHeader().getTimestamp();
|
||||||
if(aTime < bTime) return -1;
|
if (aTime < bTime) return -1;
|
||||||
if(aTime > bTime) return 1;
|
if (aTime > bTime) return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,27 +68,27 @@ implements OnClickListener {
|
|||||||
|
|
||||||
Intent i = getIntent();
|
Intent i = getIntent();
|
||||||
contactName = i.getStringExtra("briar.CONTACT_NAME");
|
contactName = i.getStringExtra("briar.CONTACT_NAME");
|
||||||
if(contactName == null) throw new IllegalStateException();
|
if (contactName == null) throw new IllegalStateException();
|
||||||
setTitle(contactName);
|
setTitle(contactName);
|
||||||
byte[] b = i.getByteArrayExtra("briar.LOCAL_AUTHOR_ID");
|
byte[] b = i.getByteArrayExtra("briar.LOCAL_AUTHOR_ID");
|
||||||
if(b == null) throw new IllegalStateException();
|
if (b == null) throw new IllegalStateException();
|
||||||
localAuthorId = new AuthorId(b);
|
localAuthorId = new AuthorId(b);
|
||||||
String authorName = i.getStringExtra("briar.AUTHOR_NAME");
|
String authorName = i.getStringExtra("briar.AUTHOR_NAME");
|
||||||
if(authorName == null) throw new IllegalStateException();
|
if (authorName == null) throw new IllegalStateException();
|
||||||
b = i.getByteArrayExtra("briar.MESSAGE_ID");
|
b = i.getByteArrayExtra("briar.MESSAGE_ID");
|
||||||
if(b == null) throw new IllegalStateException();
|
if (b == null) throw new IllegalStateException();
|
||||||
messageId = new MessageId(b);
|
messageId = new MessageId(b);
|
||||||
b = i.getByteArrayExtra("briar.GROUP_ID");
|
b = i.getByteArrayExtra("briar.GROUP_ID");
|
||||||
if(b == null) throw new IllegalStateException();
|
if (b == null) throw new IllegalStateException();
|
||||||
groupId = new GroupId(b);
|
groupId = new GroupId(b);
|
||||||
String contentType = i.getStringExtra("briar.CONTENT_TYPE");
|
String contentType = i.getStringExtra("briar.CONTENT_TYPE");
|
||||||
if(contentType == null) throw new IllegalStateException();
|
if (contentType == null) throw new IllegalStateException();
|
||||||
timestamp = i.getLongExtra("briar.TIMESTAMP", -1);
|
timestamp = i.getLongExtra("briar.TIMESTAMP", -1);
|
||||||
if(timestamp == -1) throw new IllegalStateException();
|
if (timestamp == -1) throw new IllegalStateException();
|
||||||
minTimestamp = i.getLongExtra("briar.MIN_TIMESTAMP", -1);
|
minTimestamp = i.getLongExtra("briar.MIN_TIMESTAMP", -1);
|
||||||
if(minTimestamp == -1) throw new IllegalStateException();
|
if (minTimestamp == -1) throw new IllegalStateException();
|
||||||
position = i.getIntExtra("briar.POSITION", -1);
|
position = i.getIntExtra("briar.POSITION", -1);
|
||||||
if(position == -1) throw new IllegalStateException();
|
if (position == -1) throw new IllegalStateException();
|
||||||
|
|
||||||
LinearLayout layout = new LinearLayout(this);
|
LinearLayout layout = new LinearLayout(this);
|
||||||
layout.setLayoutParams(MATCH_WRAP);
|
layout.setLayoutParams(MATCH_WRAP);
|
||||||
@@ -118,7 +118,7 @@ implements OnClickListener {
|
|||||||
header.addView(date);
|
header.addView(date);
|
||||||
message.addView(header);
|
message.addView(header);
|
||||||
|
|
||||||
if(contentType.equals("text/plain")) {
|
if (contentType.equals("text/plain")) {
|
||||||
// Load and display the message body
|
// Load and display the message body
|
||||||
content = new TextView(this);
|
content = new TextView(this);
|
||||||
content.setPadding(pad, 0, pad, pad);
|
content.setPadding(pad, 0, pad, pad);
|
||||||
@@ -164,7 +164,7 @@ implements OnClickListener {
|
|||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
if(isFinishing()) markMessageRead();
|
if (isFinishing()) markMessageRead();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markMessageRead() {
|
private void markMessageRead() {
|
||||||
@@ -174,10 +174,10 @@ implements OnClickListener {
|
|||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
db.setReadFlag(messageId, true);
|
db.setReadFlag(messageId, true);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Marking read took " + duration + " ms");
|
LOG.info("Marking read took " + duration + " ms");
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,13 +191,13 @@ implements OnClickListener {
|
|||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
byte[] body = db.getMessageBody(messageId);
|
byte[] body = db.getMessageBody(messageId);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Loading message took " + duration + " ms");
|
LOG.info("Loading message took " + duration + " ms");
|
||||||
displayMessageBody(StringUtils.fromUtf8(body));
|
displayMessageBody(StringUtils.fromUtf8(body));
|
||||||
} catch(NoSuchMessageException e) {
|
} catch (NoSuchMessageException e) {
|
||||||
finishOnUiThread();
|
finishOnUiThread();
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -213,17 +213,17 @@ implements OnClickListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
if(view == prevButton) {
|
if (view == prevButton) {
|
||||||
Intent i = new Intent();
|
Intent i = new Intent();
|
||||||
i.putExtra("briar.POSITION", position - 1);
|
i.putExtra("briar.POSITION", position - 1);
|
||||||
setResult(RESULT_PREV_NEXT, i);
|
setResult(RESULT_PREV_NEXT, i);
|
||||||
finish();
|
finish();
|
||||||
} else if(view == nextButton) {
|
} else if (view == nextButton) {
|
||||||
Intent i = new Intent();
|
Intent i = new Intent();
|
||||||
i.putExtra("briar.POSITION", position + 1);
|
i.putExtra("briar.POSITION", position + 1);
|
||||||
setResult(RESULT_PREV_NEXT, i);
|
setResult(RESULT_PREV_NEXT, i);
|
||||||
finish();
|
finish();
|
||||||
} else if(view == replyButton) {
|
} else if (view == replyButton) {
|
||||||
Intent i = new Intent(this, WritePrivateMessageActivity.class);
|
Intent i = new Intent(this, WritePrivateMessageActivity.class);
|
||||||
i.putExtra("briar.CONTACT_NAME", contactName);
|
i.putExtra("briar.CONTACT_NAME", contactName);
|
||||||
i.putExtra("briar.GROUP_ID", groupId.getBytes());
|
i.putExtra("briar.GROUP_ID", groupId.getBytes());
|
||||||
|
|||||||
@@ -35,13 +35,13 @@ public class SelectContactsDialog implements OnMultiChoiceClickListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Dialog build(Context ctx) {
|
public Dialog build(Context ctx) {
|
||||||
if(listener == null || contacts == null || selected == null)
|
if (listener == null || contacts == null || selected == null)
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
|
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
|
||||||
int size = contacts.size();
|
int size = contacts.size();
|
||||||
String[] names = new String[size];
|
String[] names = new String[size];
|
||||||
boolean[] checked = new boolean[size];
|
boolean[] checked = new boolean[size];
|
||||||
for(int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
Contact c = contacts.get(i);
|
Contact c = contacts.get(i);
|
||||||
names[i] = c.getAuthor().getName();
|
names[i] = c.getAuthor().getName();
|
||||||
checked[i] = selected.contains(c.getId());
|
checked[i] = selected.contains(c.getId());
|
||||||
@@ -63,7 +63,7 @@ public class SelectContactsDialog implements OnMultiChoiceClickListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
|
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
|
||||||
if(isChecked) selected.add(contacts.get(which).getId());
|
if (isChecked) selected.add(contacts.get(which).getId());
|
||||||
else selected.remove(contacts.get(which).getId());
|
else selected.remove(contacts.get(which).getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,18 +78,18 @@ implements OnClickListener {
|
|||||||
|
|
||||||
Intent i = getIntent();
|
Intent i = getIntent();
|
||||||
contactName = i.getStringExtra("briar.CONTACT_NAME");
|
contactName = i.getStringExtra("briar.CONTACT_NAME");
|
||||||
if(contactName == null) throw new IllegalStateException();
|
if (contactName == null) throw new IllegalStateException();
|
||||||
setTitle(contactName);
|
setTitle(contactName);
|
||||||
byte[] b = i.getByteArrayExtra("briar.GROUP_ID");
|
byte[] b = i.getByteArrayExtra("briar.GROUP_ID");
|
||||||
if(b == null) throw new IllegalStateException();
|
if (b == null) throw new IllegalStateException();
|
||||||
groupId = new GroupId(b);
|
groupId = new GroupId(b);
|
||||||
b = i.getByteArrayExtra("briar.LOCAL_AUTHOR_ID");
|
b = i.getByteArrayExtra("briar.LOCAL_AUTHOR_ID");
|
||||||
if(b == null) throw new IllegalStateException();
|
if (b == null) throw new IllegalStateException();
|
||||||
minTimestamp = i.getLongExtra("briar.MIN_TIMESTAMP", -1);
|
minTimestamp = i.getLongExtra("briar.MIN_TIMESTAMP", -1);
|
||||||
if(minTimestamp == -1) throw new IllegalStateException();
|
if (minTimestamp == -1) throw new IllegalStateException();
|
||||||
localAuthorId = new AuthorId(b);
|
localAuthorId = new AuthorId(b);
|
||||||
b = i.getByteArrayExtra("briar.PARENT_ID");
|
b = i.getByteArrayExtra("briar.PARENT_ID");
|
||||||
if(b != null) parentId = new MessageId(b);
|
if (b != null) parentId = new MessageId(b);
|
||||||
|
|
||||||
LinearLayout layout = new LinearLayout(this);
|
LinearLayout layout = new LinearLayout(this);
|
||||||
layout.setLayoutParams(MATCH_WRAP);
|
layout.setLayoutParams(MATCH_WRAP);
|
||||||
@@ -138,7 +138,7 @@ implements OnClickListener {
|
|||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
if(localAuthor == null || group == null) loadAuthorAndGroup();
|
if (localAuthor == null || group == null) loadAuthorAndGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadAuthorAndGroup() {
|
private void loadAuthorAndGroup() {
|
||||||
@@ -149,15 +149,15 @@ implements OnClickListener {
|
|||||||
localAuthor = db.getLocalAuthor(localAuthorId);
|
localAuthor = db.getLocalAuthor(localAuthorId);
|
||||||
group = db.getGroup(groupId);
|
group = db.getGroup(groupId);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Load took " + duration + " ms");
|
LOG.info("Load took " + duration + " ms");
|
||||||
displayLocalAuthor();
|
displayLocalAuthor();
|
||||||
} catch(NoSuchContactException e) {
|
} catch (NoSuchContactException e) {
|
||||||
finishOnUiThread();
|
finishOnUiThread();
|
||||||
} catch(NoSuchSubscriptionException e) {
|
} catch (NoSuchSubscriptionException e) {
|
||||||
finishOnUiThread();
|
finishOnUiThread();
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -177,7 +177,7 @@ implements OnClickListener {
|
|||||||
|
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
String message = content.getText().toString();
|
String message = content.getText().toString();
|
||||||
if(message.equals("")) return;
|
if (message.equals("")) return;
|
||||||
createMessage(StringUtils.toUtf8(message));
|
createMessage(StringUtils.toUtf8(message));
|
||||||
Toast.makeText(this, R.string.message_sent_toast, LENGTH_LONG).show();
|
Toast.makeText(this, R.string.message_sent_toast, LENGTH_LONG).show();
|
||||||
finish();
|
finish();
|
||||||
@@ -193,9 +193,9 @@ implements OnClickListener {
|
|||||||
Message m = messageFactory.createAnonymousMessage(parentId,
|
Message m = messageFactory.createAnonymousMessage(parentId,
|
||||||
group, "text/plain", timestamp, body);
|
group, "text/plain", timestamp, body);
|
||||||
storeMessage(m);
|
storeMessage(m);
|
||||||
} catch(GeneralSecurityException e) {
|
} catch (GeneralSecurityException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -209,10 +209,10 @@ implements OnClickListener {
|
|||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
db.addLocalMessage(m);
|
db.addLocalMessage(m);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Storing message took " + duration + " ms");
|
LOG.info("Storing message took " + duration + " ms");
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,21 +78,21 @@ implements EventListener, OnItemClickListener {
|
|||||||
Collection<GroupContacts> available =
|
Collection<GroupContacts> available =
|
||||||
new ArrayList<GroupContacts>();
|
new ArrayList<GroupContacts>();
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
for(Group g : db.getAvailableGroups()) {
|
for (Group g : db.getAvailableGroups()) {
|
||||||
try {
|
try {
|
||||||
GroupId id = g.getId();
|
GroupId id = g.getId();
|
||||||
Collection<Contact> c = db.getSubscribers(id);
|
Collection<Contact> c = db.getSubscribers(id);
|
||||||
available.add(new GroupContacts(g, c));
|
available.add(new GroupContacts(g, c));
|
||||||
} catch(NoSuchSubscriptionException e) {
|
} catch (NoSuchSubscriptionException e) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Load took " + duration + " ms");
|
LOG.info("Load took " + duration + " ms");
|
||||||
displayGroups(available);
|
displayGroups(available);
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -102,13 +102,13 @@ implements EventListener, OnItemClickListener {
|
|||||||
private void displayGroups(final Collection<GroupContacts> available) {
|
private void displayGroups(final Collection<GroupContacts> available) {
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
if(available.isEmpty()) {
|
if (available.isEmpty()) {
|
||||||
LOG.info("No groups available, finishing");
|
LOG.info("No groups available, finishing");
|
||||||
finish();
|
finish();
|
||||||
} else {
|
} else {
|
||||||
setContentView(list);
|
setContentView(list);
|
||||||
adapter.clear();
|
adapter.clear();
|
||||||
for(GroupContacts g : available)
|
for (GroupContacts g : available)
|
||||||
adapter.add(new AvailableGroupsItem(g));
|
adapter.add(new AvailableGroupsItem(g));
|
||||||
adapter.sort(AvailableGroupsItemComparator.INSTANCE);
|
adapter.sort(AvailableGroupsItemComparator.INSTANCE);
|
||||||
adapter.notifyDataSetChanged();
|
adapter.notifyDataSetChanged();
|
||||||
@@ -124,13 +124,13 @@ implements EventListener, OnItemClickListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if(e instanceof RemoteSubscriptionsUpdatedEvent) {
|
if (e instanceof RemoteSubscriptionsUpdatedEvent) {
|
||||||
LOG.info("Remote subscriptions changed, reloading");
|
LOG.info("Remote subscriptions changed, reloading");
|
||||||
loadGroups();
|
loadGroups();
|
||||||
} else if(e instanceof SubscriptionAddedEvent) {
|
} else if (e instanceof SubscriptionAddedEvent) {
|
||||||
LOG.info("Subscription added, reloading");
|
LOG.info("Subscription added, reloading");
|
||||||
loadGroups();
|
loadGroups();
|
||||||
} else if(e instanceof SubscriptionRemovedEvent) {
|
} else if (e instanceof SubscriptionRemovedEvent) {
|
||||||
LOG.info("Subscription removed, reloading");
|
LOG.info("Subscription removed, reloading");
|
||||||
loadGroups();
|
loadGroups();
|
||||||
}
|
}
|
||||||
@@ -140,7 +140,7 @@ implements EventListener, OnItemClickListener {
|
|||||||
long id) {
|
long id) {
|
||||||
AvailableGroupsItem item = adapter.getItem(position);
|
AvailableGroupsItem item = adapter.getItem(position);
|
||||||
Collection<ContactId> visible = new ArrayList<ContactId>();
|
Collection<ContactId> visible = new ArrayList<ContactId>();
|
||||||
for(Contact c : item.getContacts()) visible.add(c.getId());
|
for (Contact c : item.getContacts()) visible.add(c.getId());
|
||||||
addSubscription(item.getGroup(), visible);
|
addSubscription(item.getGroup(), visible);
|
||||||
String subscribed = getString(R.string.subscribed_toast);
|
String subscribed = getString(R.string.subscribed_toast);
|
||||||
Toast.makeText(this, subscribed, LENGTH_SHORT).show();
|
Toast.makeText(this, subscribed, LENGTH_SHORT).show();
|
||||||
@@ -153,8 +153,8 @@ implements EventListener, OnItemClickListener {
|
|||||||
try {
|
try {
|
||||||
db.addGroup(g);
|
db.addGroup(g);
|
||||||
db.setVisibility(g.getId(), visible);
|
db.setVisibility(g.getId(), visible);
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class AvailableGroupsAdapter extends ArrayAdapter<AvailableGroupsItem> {
|
|||||||
TextView status = new TextView(ctx);
|
TextView status = new TextView(ctx);
|
||||||
status.setPadding(pad, 0, pad, pad);
|
status.setPadding(pad, 0, pad, pad);
|
||||||
Collection<String> names = new ArrayList<String>();
|
Collection<String> names = new ArrayList<String>();
|
||||||
for(Contact c : item.getContacts()) names.add(c.getAuthor().getName());
|
for (Contact c : item.getContacts()) names.add(c.getAuthor().getName());
|
||||||
String format = ctx.getString(R.string.shared_by_format);
|
String format = ctx.getString(R.string.shared_by_format);
|
||||||
status.setText(String.format(format, StringUtils.join(names, ", ")));
|
status.setText(String.format(format, StringUtils.join(names, ", ")));
|
||||||
layout.addView(status);
|
layout.addView(status);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ class AvailableGroupsItemComparator implements Comparator<AvailableGroupsItem> {
|
|||||||
new AvailableGroupsItemComparator();
|
new AvailableGroupsItemComparator();
|
||||||
|
|
||||||
public int compare(AvailableGroupsItem a, AvailableGroupsItem b) {
|
public int compare(AvailableGroupsItem a, AvailableGroupsItem b) {
|
||||||
if(a == b) return 0;
|
if (a == b) return 0;
|
||||||
String aName = a.getGroup().getName();
|
String aName = a.getGroup().getName();
|
||||||
String bName = b.getGroup().getName();
|
String bName = b.getGroup().getName();
|
||||||
return String.CASE_INSENSITIVE_ORDER.compare(aName, bName);
|
return String.CASE_INSENSITIVE_ORDER.compare(aName, bName);
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ implements OnEditorActionListener, OnClickListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void enableOrDisableCreateButton() {
|
private void enableOrDisableCreateButton() {
|
||||||
if(progress == null) return; // Not created yet
|
if (progress == null) return; // Not created yet
|
||||||
createForumButton.setEnabled(validateName());
|
createForumButton.setEnabled(validateName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ implements OnEditorActionListener, OnClickListener {
|
|||||||
|
|
||||||
private boolean validateName() {
|
private boolean validateName() {
|
||||||
int length = StringUtils.toUtf8(nameEntry.getText().toString()).length;
|
int length = StringUtils.toUtf8(nameEntry.getText().toString()).length;
|
||||||
if(length > MAX_GROUP_NAME_LENGTH) {
|
if (length > MAX_GROUP_NAME_LENGTH) {
|
||||||
feedback.setText(R.string.name_too_long);
|
feedback.setText(R.string.name_too_long);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -125,9 +125,9 @@ implements OnEditorActionListener, OnClickListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
if(view == createForumButton) {
|
if (view == createForumButton) {
|
||||||
hideSoftKeyboard();
|
hideSoftKeyboard();
|
||||||
if(!validateName()) return;
|
if (!validateName()) return;
|
||||||
createForumButton.setVisibility(GONE);
|
createForumButton.setVisibility(GONE);
|
||||||
progress.setVisibility(VISIBLE);
|
progress.setVisibility(VISIBLE);
|
||||||
storeGroup(nameEntry.getText().toString());
|
storeGroup(nameEntry.getText().toString());
|
||||||
@@ -142,11 +142,11 @@ implements OnEditorActionListener, OnClickListener {
|
|||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
db.addGroup(g);
|
db.addGroup(g);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Storing group took " + duration + " ms");
|
LOG.info("Storing group took " + duration + " ms");
|
||||||
displayGroup(g);
|
displayGroup(g);
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
finishOnUiThread();
|
finishOnUiThread();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,10 +83,10 @@ OnClickListener, OnItemClickListener {
|
|||||||
|
|
||||||
Intent i = getIntent();
|
Intent i = getIntent();
|
||||||
byte[] b = i.getByteArrayExtra("briar.GROUP_ID");
|
byte[] b = i.getByteArrayExtra("briar.GROUP_ID");
|
||||||
if(b == null) throw new IllegalStateException();
|
if (b == null) throw new IllegalStateException();
|
||||||
groupId = new GroupId(b);
|
groupId = new GroupId(b);
|
||||||
String name = i.getStringExtra("briar.GROUP_NAME");
|
String name = i.getStringExtra("briar.GROUP_NAME");
|
||||||
if(name != null) setTitle(name);
|
if (name != null) setTitle(name);
|
||||||
|
|
||||||
LinearLayout layout = new LinearLayout(this);
|
LinearLayout layout = new LinearLayout(this);
|
||||||
layout.setLayoutParams(MATCH_MATCH);
|
layout.setLayoutParams(MATCH_MATCH);
|
||||||
@@ -155,13 +155,13 @@ OnClickListener, OnItemClickListener {
|
|||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
group = db.getGroup(groupId);
|
group = db.getGroup(groupId);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Loading group " + duration + " ms");
|
LOG.info("Loading group " + duration + " ms");
|
||||||
displayGroupName();
|
displayGroupName();
|
||||||
} catch(NoSuchSubscriptionException e) {
|
} catch (NoSuchSubscriptionException e) {
|
||||||
finishOnUiThread();
|
finishOnUiThread();
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -184,13 +184,13 @@ OnClickListener, OnItemClickListener {
|
|||||||
Collection<MessageHeader> headers =
|
Collection<MessageHeader> headers =
|
||||||
db.getMessageHeaders(groupId);
|
db.getMessageHeaders(groupId);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Load took " + duration + " ms");
|
LOG.info("Load took " + duration + " ms");
|
||||||
displayHeaders(headers);
|
displayHeaders(headers);
|
||||||
} catch(NoSuchSubscriptionException e) {
|
} catch (NoSuchSubscriptionException e) {
|
||||||
finishOnUiThread();
|
finishOnUiThread();
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,16 +202,16 @@ OnClickListener, OnItemClickListener {
|
|||||||
public void run() {
|
public void run() {
|
||||||
loading.setVisibility(GONE);
|
loading.setVisibility(GONE);
|
||||||
adapter.clear();
|
adapter.clear();
|
||||||
if(headers.isEmpty()) {
|
if (headers.isEmpty()) {
|
||||||
empty.setVisibility(VISIBLE);
|
empty.setVisibility(VISIBLE);
|
||||||
list.setVisibility(GONE);
|
list.setVisibility(GONE);
|
||||||
} else {
|
} else {
|
||||||
empty.setVisibility(GONE);
|
empty.setVisibility(GONE);
|
||||||
list.setVisibility(VISIBLE);
|
list.setVisibility(VISIBLE);
|
||||||
for(MessageHeader h : headers) {
|
for (MessageHeader h : headers) {
|
||||||
GroupItem item = new GroupItem(h);
|
GroupItem item = new GroupItem(h);
|
||||||
byte[] body = bodyCache.get(h.getId());
|
byte[] body = bodyCache.get(h.getId());
|
||||||
if(body == null) loadMessageBody(h);
|
if (body == null) loadMessageBody(h);
|
||||||
else item.setBody(body);
|
else item.setBody(body);
|
||||||
adapter.add(item);
|
adapter.add(item);
|
||||||
}
|
}
|
||||||
@@ -231,13 +231,13 @@ OnClickListener, OnItemClickListener {
|
|||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
byte[] body = db.getMessageBody(h.getId());
|
byte[] body = db.getMessageBody(h.getId());
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Loading message took " + duration + " ms");
|
LOG.info("Loading message took " + duration + " ms");
|
||||||
displayMessage(h.getId(), body);
|
displayMessage(h.getId(), body);
|
||||||
} catch(NoSuchMessageException e) {
|
} catch (NoSuchMessageException e) {
|
||||||
// The item will be removed when we get the event
|
// The item will be removed when we get the event
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -249,9 +249,9 @@ OnClickListener, OnItemClickListener {
|
|||||||
public void run() {
|
public void run() {
|
||||||
bodyCache.put(m, body);
|
bodyCache.put(m, body);
|
||||||
int count = adapter.getCount();
|
int count = adapter.getCount();
|
||||||
for(int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
GroupItem item = adapter.getItem(i);
|
GroupItem item = adapter.getItem(i);
|
||||||
if(item.getHeader().getId().equals(m)) {
|
if (item.getHeader().getId().equals(m)) {
|
||||||
item.setBody(body);
|
item.setBody(body);
|
||||||
adapter.notifyDataSetChanged();
|
adapter.notifyDataSetChanged();
|
||||||
// Scroll to the bottom
|
// Scroll to the bottom
|
||||||
@@ -266,9 +266,9 @@ OnClickListener, OnItemClickListener {
|
|||||||
@Override
|
@Override
|
||||||
protected void onActivityResult(int request, int result, Intent data) {
|
protected void onActivityResult(int request, int result, Intent data) {
|
||||||
super.onActivityResult(request, result, data);
|
super.onActivityResult(request, result, data);
|
||||||
if(request == REQUEST_READ && result == RESULT_PREV_NEXT) {
|
if (request == REQUEST_READ && result == RESULT_PREV_NEXT) {
|
||||||
int position = data.getIntExtra("briar.POSITION", -1);
|
int position = data.getIntExtra("briar.POSITION", -1);
|
||||||
if(position >= 0 && position < adapter.getCount())
|
if (position >= 0 && position < adapter.getCount())
|
||||||
displayMessage(position);
|
displayMessage(position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -277,19 +277,19 @@ OnClickListener, OnItemClickListener {
|
|||||||
public void onPause() {
|
public void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
eventBus.removeListener(this);
|
eventBus.removeListener(this);
|
||||||
if(isFinishing()) markMessagesRead();
|
if (isFinishing()) markMessagesRead();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markMessagesRead() {
|
private void markMessagesRead() {
|
||||||
notificationManager.clearGroupPostNotification(groupId);
|
notificationManager.clearGroupPostNotification(groupId);
|
||||||
List<MessageId> unread = new ArrayList<MessageId>();
|
List<MessageId> unread = new ArrayList<MessageId>();
|
||||||
int count = adapter.getCount();
|
int count = adapter.getCount();
|
||||||
for(int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
MessageHeader h = adapter.getItem(i).getHeader();
|
MessageHeader h = adapter.getItem(i).getHeader();
|
||||||
if(!h.isRead()) unread.add(h.getId());
|
if (!h.isRead()) unread.add(h.getId());
|
||||||
}
|
}
|
||||||
if(unread.isEmpty()) return;
|
if (unread.isEmpty()) return;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Marking " + unread.size() + " messages read");
|
LOG.info("Marking " + unread.size() + " messages read");
|
||||||
markMessagesRead(Collections.unmodifiableList(unread));
|
markMessagesRead(Collections.unmodifiableList(unread));
|
||||||
}
|
}
|
||||||
@@ -299,12 +299,12 @@ OnClickListener, OnItemClickListener {
|
|||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
for(MessageId m : unread) db.setReadFlag(m, true);
|
for (MessageId m : unread) db.setReadFlag(m, true);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Marking read took " + duration + " ms");
|
LOG.info("Marking read took " + duration + " ms");
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -312,17 +312,17 @@ OnClickListener, OnItemClickListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if(e instanceof MessageAddedEvent) {
|
if (e instanceof MessageAddedEvent) {
|
||||||
if(((MessageAddedEvent) e).getGroup().getId().equals(groupId)) {
|
if (((MessageAddedEvent) e).getGroup().getId().equals(groupId)) {
|
||||||
LOG.info("Message added, reloading");
|
LOG.info("Message added, reloading");
|
||||||
loadHeaders();
|
loadHeaders();
|
||||||
}
|
}
|
||||||
} else if(e instanceof MessageExpiredEvent) {
|
} else if (e instanceof MessageExpiredEvent) {
|
||||||
LOG.info("Message expired, reloading");
|
LOG.info("Message expired, reloading");
|
||||||
loadHeaders();
|
loadHeaders();
|
||||||
} else if(e instanceof SubscriptionRemovedEvent) {
|
} else if (e instanceof SubscriptionRemovedEvent) {
|
||||||
SubscriptionRemovedEvent s = (SubscriptionRemovedEvent) e;
|
SubscriptionRemovedEvent s = (SubscriptionRemovedEvent) e;
|
||||||
if(s.getGroup().getId().equals(groupId)) {
|
if (s.getGroup().getId().equals(groupId)) {
|
||||||
LOG.info("Subscription removed");
|
LOG.info("Subscription removed");
|
||||||
finishOnUiThread();
|
finishOnUiThread();
|
||||||
}
|
}
|
||||||
@@ -330,13 +330,13 @@ OnClickListener, OnItemClickListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
if(view == composeButton) {
|
if (view == composeButton) {
|
||||||
Intent i = new Intent(this, WriteGroupPostActivity.class);
|
Intent i = new Intent(this, WriteGroupPostActivity.class);
|
||||||
i.putExtra("briar.GROUP_ID", groupId.getBytes());
|
i.putExtra("briar.GROUP_ID", groupId.getBytes());
|
||||||
i.putExtra("briar.GROUP_NAME", group.getName());
|
i.putExtra("briar.GROUP_NAME", group.getName());
|
||||||
i.putExtra("briar.MIN_TIMESTAMP", getMinTimestampForNewMessage());
|
i.putExtra("briar.MIN_TIMESTAMP", getMinTimestampForNewMessage());
|
||||||
startActivity(i);
|
startActivity(i);
|
||||||
} else if(view == shareButton) {
|
} else if (view == shareButton) {
|
||||||
Intent i = new Intent(this, ShareGroupActivity.class);
|
Intent i = new Intent(this, ShareGroupActivity.class);
|
||||||
i.putExtra("briar.GROUP_ID", groupId.getBytes());
|
i.putExtra("briar.GROUP_ID", groupId.getBytes());
|
||||||
i.putExtra("briar.GROUP_NAME", group.getName());
|
i.putExtra("briar.GROUP_NAME", group.getName());
|
||||||
@@ -348,9 +348,9 @@ OnClickListener, OnItemClickListener {
|
|||||||
// Don't use an earlier timestamp than the newest message
|
// Don't use an earlier timestamp than the newest message
|
||||||
long timestamp = 0;
|
long timestamp = 0;
|
||||||
int count = adapter.getCount();
|
int count = adapter.getCount();
|
||||||
for(int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
long t = adapter.getItem(i).getHeader().getTimestamp();
|
long t = adapter.getItem(i).getHeader().getTimestamp();
|
||||||
if(t > timestamp) timestamp = t;
|
if (t > timestamp) timestamp = t;
|
||||||
}
|
}
|
||||||
return timestamp + 1;
|
return timestamp + 1;
|
||||||
}
|
}
|
||||||
@@ -367,7 +367,7 @@ OnClickListener, OnItemClickListener {
|
|||||||
i.putExtra("briar.GROUP_NAME", group.getName());
|
i.putExtra("briar.GROUP_NAME", group.getName());
|
||||||
i.putExtra("briar.MESSAGE_ID", item.getId().getBytes());
|
i.putExtra("briar.MESSAGE_ID", item.getId().getBytes());
|
||||||
Author author = item.getAuthor();
|
Author author = item.getAuthor();
|
||||||
if(author != null) i.putExtra("briar.AUTHOR_NAME", author.getName());
|
if (author != null) i.putExtra("briar.AUTHOR_NAME", author.getName());
|
||||||
i.putExtra("briar.AUTHOR_STATUS", item.getAuthorStatus().name());
|
i.putExtra("briar.AUTHOR_STATUS", item.getAuthorStatus().name());
|
||||||
i.putExtra("briar.CONTENT_TYPE", item.getContentType());
|
i.putExtra("briar.CONTENT_TYPE", item.getContentType());
|
||||||
i.putExtra("briar.TIMESTAMP", item.getTimestamp());
|
i.putExtra("briar.TIMESTAMP", item.getTimestamp());
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class GroupAdapter extends ArrayAdapter<GroupItem> {
|
|||||||
LinearLayout layout = new LinearLayout(ctx);
|
LinearLayout layout = new LinearLayout(ctx);
|
||||||
layout.setOrientation(VERTICAL);
|
layout.setOrientation(VERTICAL);
|
||||||
layout.setGravity(CENTER_HORIZONTAL);
|
layout.setGravity(CENTER_HORIZONTAL);
|
||||||
if(!header.isRead())
|
if (!header.isRead())
|
||||||
layout.setBackgroundColor(res.getColor(R.color.unread_background));
|
layout.setBackgroundColor(res.getColor(R.color.unread_background));
|
||||||
|
|
||||||
LinearLayout headerLayout = new LinearLayout(ctx);
|
LinearLayout headerLayout = new LinearLayout(ctx);
|
||||||
@@ -55,7 +55,7 @@ class GroupAdapter extends ArrayAdapter<GroupItem> {
|
|||||||
AuthorView authorView = new AuthorView(ctx);
|
AuthorView authorView = new AuthorView(ctx);
|
||||||
authorView.setLayoutParams(WRAP_WRAP_1);
|
authorView.setLayoutParams(WRAP_WRAP_1);
|
||||||
Author author = header.getAuthor();
|
Author author = header.getAuthor();
|
||||||
if(author == null) authorView.init(null, header.getAuthorStatus());
|
if (author == null) authorView.init(null, header.getAuthorStatus());
|
||||||
else authorView.init(author.getName(), header.getAuthorStatus());
|
else authorView.init(author.getName(), header.getAuthorStatus());
|
||||||
headerLayout.addView(authorView);
|
headerLayout.addView(authorView);
|
||||||
|
|
||||||
@@ -66,12 +66,12 @@ class GroupAdapter extends ArrayAdapter<GroupItem> {
|
|||||||
headerLayout.addView(date);
|
headerLayout.addView(date);
|
||||||
layout.addView(headerLayout);
|
layout.addView(headerLayout);
|
||||||
|
|
||||||
if(item.getBody() == null) {
|
if (item.getBody() == null) {
|
||||||
TextView ellipsis = new TextView(ctx);
|
TextView ellipsis = new TextView(ctx);
|
||||||
ellipsis.setPadding(pad, 0, pad, pad);
|
ellipsis.setPadding(pad, 0, pad, pad);
|
||||||
ellipsis.setText("\u2026");
|
ellipsis.setText("\u2026");
|
||||||
layout.addView(ellipsis);
|
layout.addView(ellipsis);
|
||||||
} else if(header.getContentType().equals("text/plain")) {
|
} else if (header.getContentType().equals("text/plain")) {
|
||||||
TextView text = new TextView(ctx);
|
TextView text = new TextView(ctx);
|
||||||
text.setPadding(pad, 0, pad, pad);
|
text.setPadding(pad, 0, pad, pad);
|
||||||
text.setText(StringUtils.fromUtf8(item.getBody()));
|
text.setText(StringUtils.fromUtf8(item.getBody()));
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ class GroupItemComparator implements Comparator<GroupItem> {
|
|||||||
// The oldest message comes first
|
// The oldest message comes first
|
||||||
long aTime = a.getHeader().getTimestamp();
|
long aTime = a.getHeader().getTimestamp();
|
||||||
long bTime = b.getHeader().getTimestamp();
|
long bTime = b.getHeader().getTimestamp();
|
||||||
if(aTime < bTime) return -1;
|
if (aTime < bTime) return -1;
|
||||||
if(aTime > bTime) return 1;
|
if (aTime > bTime) return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -154,20 +154,20 @@ OnCreateContextMenuListener {
|
|||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
for(Group g : db.getGroups()) {
|
for (Group g : db.getGroups()) {
|
||||||
try {
|
try {
|
||||||
displayHeaders(g, db.getMessageHeaders(g.getId()));
|
displayHeaders(g, db.getMessageHeaders(g.getId()));
|
||||||
} catch(NoSuchSubscriptionException e) {
|
} catch (NoSuchSubscriptionException e) {
|
||||||
// Continue
|
// Continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int available = db.getAvailableGroups().size();
|
int available = db.getAvailableGroups().size();
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Full load took " + duration + " ms");
|
LOG.info("Full load took " + duration + " ms");
|
||||||
displayAvailable(available);
|
displayAvailable(available);
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,7 +198,7 @@ OnCreateContextMenuListener {
|
|||||||
loading.setVisibility(GONE);
|
loading.setVisibility(GONE);
|
||||||
// Remove the old item, if any
|
// Remove the old item, if any
|
||||||
GroupListItem item = findGroup(id);
|
GroupListItem item = findGroup(id);
|
||||||
if(item != null) adapter.remove(item);
|
if (item != null) adapter.remove(item);
|
||||||
// Add a new item
|
// Add a new item
|
||||||
adapter.add(new GroupListItem(g, headers));
|
adapter.add(new GroupListItem(g, headers));
|
||||||
adapter.sort(GroupListItemComparator.INSTANCE);
|
adapter.sort(GroupListItemComparator.INSTANCE);
|
||||||
@@ -211,9 +211,9 @@ OnCreateContextMenuListener {
|
|||||||
private void displayAvailable(final int availableCount) {
|
private void displayAvailable(final int availableCount) {
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
if(adapter.isEmpty()) empty.setVisibility(VISIBLE);
|
if (adapter.isEmpty()) empty.setVisibility(VISIBLE);
|
||||||
loading.setVisibility(GONE);
|
loading.setVisibility(GONE);
|
||||||
if(availableCount == 0) {
|
if (availableCount == 0) {
|
||||||
available.setVisibility(GONE);
|
available.setVisibility(GONE);
|
||||||
} else {
|
} else {
|
||||||
available.setVisibility(VISIBLE);
|
available.setVisibility(VISIBLE);
|
||||||
@@ -227,22 +227,22 @@ OnCreateContextMenuListener {
|
|||||||
|
|
||||||
private GroupListItem findGroup(GroupId g) {
|
private GroupListItem findGroup(GroupId g) {
|
||||||
int count = adapter.getCount();
|
int count = adapter.getCount();
|
||||||
for(int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
GroupListItem item = adapter.getItem(i);
|
GroupListItem item = adapter.getItem(i);
|
||||||
if(item.getGroup().getId().equals(g)) return item;
|
if (item.getGroup().getId().equals(g)) return item;
|
||||||
}
|
}
|
||||||
return null; // Not found
|
return null; // Not found
|
||||||
}
|
}
|
||||||
|
|
||||||
private void selectFirstUnread() {
|
private void selectFirstUnread() {
|
||||||
int firstUnread = -1, count = adapter.getCount();
|
int firstUnread = -1, count = adapter.getCount();
|
||||||
for(int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
if(adapter.getItem(i).getUnreadCount() > 0) {
|
if (adapter.getItem(i).getUnreadCount() > 0) {
|
||||||
firstUnread = i;
|
firstUnread = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(firstUnread == -1) list.setSelection(count - 1);
|
if (firstUnread == -1) list.setSelection(count - 1);
|
||||||
else list.setSelection(firstUnread);
|
else list.setSelection(firstUnread);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,24 +253,24 @@ OnCreateContextMenuListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if(e instanceof MessageAddedEvent) {
|
if (e instanceof MessageAddedEvent) {
|
||||||
Group g = ((MessageAddedEvent) e).getGroup();
|
Group g = ((MessageAddedEvent) e).getGroup();
|
||||||
if(groups.containsKey(g.getId())) {
|
if (groups.containsKey(g.getId())) {
|
||||||
LOG.info("Message added, reloading");
|
LOG.info("Message added, reloading");
|
||||||
loadHeaders(g);
|
loadHeaders(g);
|
||||||
}
|
}
|
||||||
} else if(e instanceof MessageExpiredEvent) {
|
} else if (e instanceof MessageExpiredEvent) {
|
||||||
LOG.info("Message expired, reloading");
|
LOG.info("Message expired, reloading");
|
||||||
loadHeaders();
|
loadHeaders();
|
||||||
} else if(e instanceof RemoteSubscriptionsUpdatedEvent) {
|
} else if (e instanceof RemoteSubscriptionsUpdatedEvent) {
|
||||||
LOG.info("Remote subscriptions changed, reloading");
|
LOG.info("Remote subscriptions changed, reloading");
|
||||||
loadAvailable();
|
loadAvailable();
|
||||||
} else if(e instanceof SubscriptionAddedEvent) {
|
} else if (e instanceof SubscriptionAddedEvent) {
|
||||||
LOG.info("Group added, reloading");
|
LOG.info("Group added, reloading");
|
||||||
loadHeaders();
|
loadHeaders();
|
||||||
} else if(e instanceof SubscriptionRemovedEvent) {
|
} else if (e instanceof SubscriptionRemovedEvent) {
|
||||||
Group g = ((SubscriptionRemovedEvent) e).getGroup();
|
Group g = ((SubscriptionRemovedEvent) e).getGroup();
|
||||||
if(groups.containsKey(g.getId())) {
|
if (groups.containsKey(g.getId())) {
|
||||||
LOG.info("Group removed, reloading");
|
LOG.info("Group removed, reloading");
|
||||||
loadHeaders();
|
loadHeaders();
|
||||||
}
|
}
|
||||||
@@ -285,13 +285,13 @@ OnCreateContextMenuListener {
|
|||||||
Collection<MessageHeader> headers =
|
Collection<MessageHeader> headers =
|
||||||
db.getMessageHeaders(g.getId());
|
db.getMessageHeaders(g.getId());
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Partial load took " + duration + " ms");
|
LOG.info("Partial load took " + duration + " ms");
|
||||||
displayHeaders(g, headers);
|
displayHeaders(g, headers);
|
||||||
} catch(NoSuchSubscriptionException e) {
|
} catch (NoSuchSubscriptionException e) {
|
||||||
removeGroup(g.getId());
|
removeGroup(g.getId());
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -302,11 +302,11 @@ OnCreateContextMenuListener {
|
|||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
GroupListItem item = findGroup(g);
|
GroupListItem item = findGroup(g);
|
||||||
if(item != null) {
|
if (item != null) {
|
||||||
groups.remove(g);
|
groups.remove(g);
|
||||||
adapter.remove(item);
|
adapter.remove(item);
|
||||||
adapter.notifyDataSetChanged();
|
adapter.notifyDataSetChanged();
|
||||||
if(adapter.isEmpty()) {
|
if (adapter.isEmpty()) {
|
||||||
empty.setVisibility(VISIBLE);
|
empty.setVisibility(VISIBLE);
|
||||||
list.setVisibility(GONE);
|
list.setVisibility(GONE);
|
||||||
} else {
|
} else {
|
||||||
@@ -324,11 +324,11 @@ OnCreateContextMenuListener {
|
|||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
int available = db.getAvailableGroups().size();
|
int available = db.getAvailableGroups().size();
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Loading available took " + duration + " ms");
|
LOG.info("Loading available took " + duration + " ms");
|
||||||
displayAvailable(available);
|
displayAvailable(available);
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -336,9 +336,9 @@ OnCreateContextMenuListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
if(view == available) {
|
if (view == available) {
|
||||||
startActivity(new Intent(this, AvailableGroupsActivity.class));
|
startActivity(new Intent(this, AvailableGroupsActivity.class));
|
||||||
} else if(view == newGroupButton) {
|
} else if (view == newGroupButton) {
|
||||||
startActivity(new Intent(this, CreateGroupActivity.class));
|
startActivity(new Intent(this, CreateGroupActivity.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -361,7 +361,7 @@ OnCreateContextMenuListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onContextItemSelected(MenuItem menuItem) {
|
public boolean onContextItemSelected(MenuItem menuItem) {
|
||||||
if(menuItem.getItemId() == MENU_ITEM_UNSUBSCRIBE) {
|
if (menuItem.getItemId() == MENU_ITEM_UNSUBSCRIBE) {
|
||||||
ContextMenuInfo info = menuItem.getMenuInfo();
|
ContextMenuInfo info = menuItem.getMenuInfo();
|
||||||
int position = ((AdapterContextMenuInfo) info).position;
|
int position = ((AdapterContextMenuInfo) info).position;
|
||||||
GroupListItem item = adapter.getItem(position);
|
GroupListItem item = adapter.getItem(position);
|
||||||
@@ -379,10 +379,10 @@ OnCreateContextMenuListener {
|
|||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
db.removeGroup(g);
|
db.removeGroup(g);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Removing group took " + duration + " ms");
|
LOG.info("Removing group took " + duration + " ms");
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class GroupListAdapter extends ArrayAdapter<GroupListItem> {
|
|||||||
LinearLayout layout = new LinearLayout(ctx);
|
LinearLayout layout = new LinearLayout(ctx);
|
||||||
layout.setOrientation(HORIZONTAL);
|
layout.setOrientation(HORIZONTAL);
|
||||||
int unread = item.getUnreadCount();
|
int unread = item.getUnreadCount();
|
||||||
if(unread > 0)
|
if (unread > 0)
|
||||||
layout.setBackgroundColor(res.getColor(R.color.unread_background));
|
layout.setBackgroundColor(res.getColor(R.color.unread_background));
|
||||||
|
|
||||||
TextView name = new TextView(ctx);
|
TextView name = new TextView(ctx);
|
||||||
@@ -47,11 +47,11 @@ class GroupListAdapter extends ArrayAdapter<GroupListItem> {
|
|||||||
name.setEllipsize(END);
|
name.setEllipsize(END);
|
||||||
name.setPadding(pad, pad, pad, pad);
|
name.setPadding(pad, pad, pad, pad);
|
||||||
String groupName = item.getGroup().getName();
|
String groupName = item.getGroup().getName();
|
||||||
if(unread > 0) name.setText(groupName + " (" + unread + ")");
|
if (unread > 0) name.setText(groupName + " (" + unread + ")");
|
||||||
else name.setText(groupName);
|
else name.setText(groupName);
|
||||||
layout.addView(name);
|
layout.addView(name);
|
||||||
|
|
||||||
if(item.isEmpty()) {
|
if (item.isEmpty()) {
|
||||||
TextView noPosts = new TextView(ctx);
|
TextView noPosts = new TextView(ctx);
|
||||||
noPosts.setPadding(pad, 0, pad, pad);
|
noPosts.setPadding(pad, 0, pad, pad);
|
||||||
noPosts.setTextColor(res.getColor(R.color.no_posts));
|
noPosts.setTextColor(res.getColor(R.color.no_posts));
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class GroupListItem {
|
|||||||
GroupListItem(Group group, Collection<MessageHeader> headers) {
|
GroupListItem(Group group, Collection<MessageHeader> headers) {
|
||||||
this.group = group;
|
this.group = group;
|
||||||
empty = headers.isEmpty();
|
empty = headers.isEmpty();
|
||||||
if(empty) {
|
if (empty) {
|
||||||
authorName = null;
|
authorName = null;
|
||||||
contentType = null;
|
contentType = null;
|
||||||
timestamp = 0;
|
timestamp = 0;
|
||||||
@@ -26,15 +26,15 @@ class GroupListItem {
|
|||||||
MessageHeader newest = null;
|
MessageHeader newest = null;
|
||||||
long timestamp = 0;
|
long timestamp = 0;
|
||||||
int unread = 0;
|
int unread = 0;
|
||||||
for(MessageHeader h : headers) {
|
for (MessageHeader h : headers) {
|
||||||
if(h.getTimestamp() > timestamp) {
|
if (h.getTimestamp() > timestamp) {
|
||||||
timestamp = h.getTimestamp();
|
timestamp = h.getTimestamp();
|
||||||
newest = h;
|
newest = h;
|
||||||
}
|
}
|
||||||
if(!h.isRead()) unread++;
|
if (!h.isRead()) unread++;
|
||||||
}
|
}
|
||||||
Author a = newest.getAuthor();
|
Author a = newest.getAuthor();
|
||||||
if(a == null) authorName = null;
|
if (a == null) authorName = null;
|
||||||
else authorName = a.getName();
|
else authorName = a.getName();
|
||||||
contentType = newest.getContentType();
|
contentType = newest.getContentType();
|
||||||
this.timestamp = newest.getTimestamp();
|
this.timestamp = newest.getTimestamp();
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ class GroupListItemComparator implements Comparator<GroupListItem> {
|
|||||||
new GroupListItemComparator();
|
new GroupListItemComparator();
|
||||||
|
|
||||||
public int compare(GroupListItem a, GroupListItem b) {
|
public int compare(GroupListItem a, GroupListItem b) {
|
||||||
if(a == b) return 0;
|
if (a == b) return 0;
|
||||||
// The item with the newest message comes first
|
// The item with the newest message comes first
|
||||||
long aTime = a.getTimestamp(), bTime = b.getTimestamp();
|
long aTime = a.getTimestamp(), bTime = b.getTimestamp();
|
||||||
if(aTime > bTime) return -1;
|
if (aTime > bTime) return -1;
|
||||||
if(aTime < bTime) return 1;
|
if (aTime < bTime) return 1;
|
||||||
// Break ties by group name
|
// Break ties by group name
|
||||||
String aName = a.getGroup().getName();
|
String aName = a.getGroup().getName();
|
||||||
String bName = b.getGroup().getName();
|
String bName = b.getGroup().getName();
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ public class NoContactsDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Dialog build(Context ctx) {
|
public Dialog build(Context ctx) {
|
||||||
if(listener == null) throw new IllegalStateException();
|
if (listener == null) throw new IllegalStateException();
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
|
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
|
||||||
builder.setMessage(R.string.no_contacts_prompt);
|
builder.setMessage(R.string.no_contacts_prompt);
|
||||||
builder.setPositiveButton(R.string.add_button,
|
builder.setPositiveButton(R.string.add_button,
|
||||||
|
|||||||
@@ -66,25 +66,25 @@ implements OnClickListener {
|
|||||||
|
|
||||||
Intent i = getIntent();
|
Intent i = getIntent();
|
||||||
byte[] b = i.getByteArrayExtra("briar.GROUP_ID");
|
byte[] b = i.getByteArrayExtra("briar.GROUP_ID");
|
||||||
if(b == null) throw new IllegalStateException();
|
if (b == null) throw new IllegalStateException();
|
||||||
groupId = new GroupId(b);
|
groupId = new GroupId(b);
|
||||||
groupName = i.getStringExtra("briar.GROUP_NAME");
|
groupName = i.getStringExtra("briar.GROUP_NAME");
|
||||||
if(groupName == null) throw new IllegalStateException();
|
if (groupName == null) throw new IllegalStateException();
|
||||||
setTitle(groupName);
|
setTitle(groupName);
|
||||||
b = i.getByteArrayExtra("briar.MESSAGE_ID");
|
b = i.getByteArrayExtra("briar.MESSAGE_ID");
|
||||||
if(b == null) throw new IllegalStateException();
|
if (b == null) throw new IllegalStateException();
|
||||||
messageId = new MessageId(b);
|
messageId = new MessageId(b);
|
||||||
String contentType = i.getStringExtra("briar.CONTENT_TYPE");
|
String contentType = i.getStringExtra("briar.CONTENT_TYPE");
|
||||||
if(contentType == null) throw new IllegalStateException();
|
if (contentType == null) throw new IllegalStateException();
|
||||||
timestamp = i.getLongExtra("briar.TIMESTAMP", -1);
|
timestamp = i.getLongExtra("briar.TIMESTAMP", -1);
|
||||||
if(timestamp == -1) throw new IllegalStateException();
|
if (timestamp == -1) throw new IllegalStateException();
|
||||||
minTimestamp = i.getLongExtra("briar.MIN_TIMESTAMP", -1);
|
minTimestamp = i.getLongExtra("briar.MIN_TIMESTAMP", -1);
|
||||||
if(minTimestamp == -1) throw new IllegalStateException();
|
if (minTimestamp == -1) throw new IllegalStateException();
|
||||||
position = i.getIntExtra("briar.POSITION", -1);
|
position = i.getIntExtra("briar.POSITION", -1);
|
||||||
if(position == -1) throw new IllegalStateException();
|
if (position == -1) throw new IllegalStateException();
|
||||||
String authorName = i.getStringExtra("briar.AUTHOR_NAME");
|
String authorName = i.getStringExtra("briar.AUTHOR_NAME");
|
||||||
String s = i.getStringExtra("briar.AUTHOR_STATUS");
|
String s = i.getStringExtra("briar.AUTHOR_STATUS");
|
||||||
if(s == null) throw new IllegalStateException();
|
if (s == null) throw new IllegalStateException();
|
||||||
Author.Status authorStatus = Author.Status.valueOf(s);
|
Author.Status authorStatus = Author.Status.valueOf(s);
|
||||||
|
|
||||||
LinearLayout layout = new LinearLayout(this);
|
LinearLayout layout = new LinearLayout(this);
|
||||||
@@ -115,7 +115,7 @@ implements OnClickListener {
|
|||||||
header.addView(date);
|
header.addView(date);
|
||||||
message.addView(header);
|
message.addView(header);
|
||||||
|
|
||||||
if(contentType.equals("text/plain")) {
|
if (contentType.equals("text/plain")) {
|
||||||
// Load and display the message body
|
// Load and display the message body
|
||||||
content = new TextView(this);
|
content = new TextView(this);
|
||||||
content.setPadding(pad, 0, pad, pad);
|
content.setPadding(pad, 0, pad, pad);
|
||||||
@@ -161,7 +161,7 @@ implements OnClickListener {
|
|||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
if(isFinishing()) markMessageRead();
|
if (isFinishing()) markMessageRead();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markMessageRead() {
|
private void markMessageRead() {
|
||||||
@@ -171,10 +171,10 @@ implements OnClickListener {
|
|||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
db.setReadFlag(messageId, true);
|
db.setReadFlag(messageId, true);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Marking read took " + duration + " ms");
|
LOG.info("Marking read took " + duration + " ms");
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -188,13 +188,13 @@ implements OnClickListener {
|
|||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
byte[] body = db.getMessageBody(messageId);
|
byte[] body = db.getMessageBody(messageId);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Loading message took " + duration + " ms");
|
LOG.info("Loading message took " + duration + " ms");
|
||||||
displayMessageBody(StringUtils.fromUtf8(body));
|
displayMessageBody(StringUtils.fromUtf8(body));
|
||||||
} catch(NoSuchMessageException e) {
|
} catch (NoSuchMessageException e) {
|
||||||
finishOnUiThread();
|
finishOnUiThread();
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,17 +210,17 @@ implements OnClickListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
if(view == prevButton) {
|
if (view == prevButton) {
|
||||||
Intent i = new Intent();
|
Intent i = new Intent();
|
||||||
i.putExtra("briar.POSITION", position - 1);
|
i.putExtra("briar.POSITION", position - 1);
|
||||||
setResult(RESULT_PREV_NEXT, i);
|
setResult(RESULT_PREV_NEXT, i);
|
||||||
finish();
|
finish();
|
||||||
} else if(view == nextButton) {
|
} else if (view == nextButton) {
|
||||||
Intent i = new Intent();
|
Intent i = new Intent();
|
||||||
i.putExtra("briar.POSITION", position + 1);
|
i.putExtra("briar.POSITION", position + 1);
|
||||||
setResult(RESULT_PREV_NEXT, i);
|
setResult(RESULT_PREV_NEXT, i);
|
||||||
finish();
|
finish();
|
||||||
} else if(view == replyButton) {
|
} else if (view == replyButton) {
|
||||||
Intent i = new Intent(this, WriteGroupPostActivity.class);
|
Intent i = new Intent(this, WriteGroupPostActivity.class);
|
||||||
i.putExtra("briar.GROUP_ID", groupId.getBytes());
|
i.putExtra("briar.GROUP_ID", groupId.getBytes());
|
||||||
i.putExtra("briar.GROUP_NAME", groupName);
|
i.putExtra("briar.GROUP_NAME", groupName);
|
||||||
|
|||||||
@@ -62,10 +62,10 @@ SelectContactsDialog.Listener {
|
|||||||
|
|
||||||
Intent i = getIntent();
|
Intent i = getIntent();
|
||||||
byte[] b = i.getByteArrayExtra("briar.GROUP_ID");
|
byte[] b = i.getByteArrayExtra("briar.GROUP_ID");
|
||||||
if(b == null) throw new IllegalStateException();
|
if (b == null) throw new IllegalStateException();
|
||||||
groupId = new GroupId(b);
|
groupId = new GroupId(b);
|
||||||
groupName = i.getStringExtra("briar.GROUP_NAME");
|
groupName = i.getStringExtra("briar.GROUP_NAME");
|
||||||
if(groupName == null) throw new IllegalStateException();
|
if (groupName == null) throw new IllegalStateException();
|
||||||
setTitle(groupName);
|
setTitle(groupName);
|
||||||
|
|
||||||
LinearLayout layout = new LinearLayout(this);
|
LinearLayout layout = new LinearLayout(this);
|
||||||
@@ -109,14 +109,14 @@ SelectContactsDialog.Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
if(view == shareWithAll) {
|
if (view == shareWithAll) {
|
||||||
changed = true;
|
changed = true;
|
||||||
} else if(view == shareWithSome) {
|
} else if (view == shareWithSome) {
|
||||||
changed = true;
|
changed = true;
|
||||||
if(contacts == null) loadVisibility();
|
if (contacts == null) loadVisibility();
|
||||||
else displayVisibility();
|
else displayVisibility();
|
||||||
} else if(view == shareButton) {
|
} else if (view == shareButton) {
|
||||||
if(changed) {
|
if (changed) {
|
||||||
// Replace the button with a progress bar
|
// Replace the button with a progress bar
|
||||||
shareButton.setVisibility(GONE);
|
shareButton.setVisibility(GONE);
|
||||||
progress.setVisibility(VISIBLE);
|
progress.setVisibility(VISIBLE);
|
||||||
@@ -136,11 +136,11 @@ SelectContactsDialog.Listener {
|
|||||||
contacts = db.getContacts();
|
contacts = db.getContacts();
|
||||||
selected = db.getVisibility(groupId);
|
selected = db.getVisibility(groupId);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Load took " + duration + " ms");
|
LOG.info("Load took " + duration + " ms");
|
||||||
displayVisibility();
|
displayVisibility();
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,7 +150,7 @@ SelectContactsDialog.Listener {
|
|||||||
private void displayVisibility() {
|
private void displayVisibility() {
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
if(contacts.isEmpty()) {
|
if (contacts.isEmpty()) {
|
||||||
NoContactsDialog builder = new NoContactsDialog();
|
NoContactsDialog builder = new NoContactsDialog();
|
||||||
builder.setListener(ShareGroupActivity.this);
|
builder.setListener(ShareGroupActivity.this);
|
||||||
builder.build(ShareGroupActivity.this).show();
|
builder.build(ShareGroupActivity.this).show();
|
||||||
@@ -171,12 +171,12 @@ SelectContactsDialog.Listener {
|
|||||||
try {
|
try {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
db.setVisibleToAll(groupId, all);
|
db.setVisibleToAll(groupId, all);
|
||||||
if(!all) db.setVisibility(groupId, selected);
|
if (!all) db.setVisibility(groupId, selected);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Update took " + duration + " ms");
|
LOG.info("Update took " + duration + " ms");
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
finishOnUiThread();
|
finishOnUiThread();
|
||||||
|
|||||||
@@ -89,19 +89,19 @@ implements OnItemSelectedListener, OnClickListener {
|
|||||||
|
|
||||||
Intent i = getIntent();
|
Intent i = getIntent();
|
||||||
byte[] b = i.getByteArrayExtra("briar.GROUP_ID");
|
byte[] b = i.getByteArrayExtra("briar.GROUP_ID");
|
||||||
if(b == null) throw new IllegalStateException();
|
if (b == null) throw new IllegalStateException();
|
||||||
groupId = new GroupId(b);
|
groupId = new GroupId(b);
|
||||||
String groupName = i.getStringExtra("briar.GROUP_NAME");
|
String groupName = i.getStringExtra("briar.GROUP_NAME");
|
||||||
if(groupName == null) throw new IllegalStateException();
|
if (groupName == null) throw new IllegalStateException();
|
||||||
setTitle(groupName);
|
setTitle(groupName);
|
||||||
minTimestamp = i.getLongExtra("briar.MIN_TIMESTAMP", -1);
|
minTimestamp = i.getLongExtra("briar.MIN_TIMESTAMP", -1);
|
||||||
if(minTimestamp == -1) throw new IllegalStateException();
|
if (minTimestamp == -1) throw new IllegalStateException();
|
||||||
b = i.getByteArrayExtra("briar.PARENT_ID");
|
b = i.getByteArrayExtra("briar.PARENT_ID");
|
||||||
if(b != null) parentId = new MessageId(b);
|
if (b != null) parentId = new MessageId(b);
|
||||||
|
|
||||||
if(state != null) {
|
if (state != null) {
|
||||||
b = state.getByteArray("briar.LOCAL_AUTHOR_ID");
|
b = state.getByteArray("briar.LOCAL_AUTHOR_ID");
|
||||||
if(b != null) localAuthorId = new AuthorId(b);
|
if (b != null) localAuthorId = new AuthorId(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
LinearLayout layout = new LinearLayout(this);
|
LinearLayout layout = new LinearLayout(this);
|
||||||
@@ -169,11 +169,11 @@ implements OnItemSelectedListener, OnClickListener {
|
|||||||
Collection<LocalAuthor> localAuthors = db.getLocalAuthors();
|
Collection<LocalAuthor> localAuthors = db.getLocalAuthors();
|
||||||
group = db.getGroup(groupId);
|
group = db.getGroup(groupId);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Load took " + duration + " ms");
|
LOG.info("Load took " + duration + " ms");
|
||||||
displayAuthorsAndGroup(localAuthors);
|
displayAuthorsAndGroup(localAuthors);
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -184,18 +184,18 @@ implements OnItemSelectedListener, OnClickListener {
|
|||||||
final Collection<LocalAuthor> localAuthors) {
|
final Collection<LocalAuthor> localAuthors) {
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
if(localAuthors.isEmpty()) throw new IllegalStateException();
|
if (localAuthors.isEmpty()) throw new IllegalStateException();
|
||||||
adapter.clear();
|
adapter.clear();
|
||||||
for(LocalAuthor a : localAuthors)
|
for (LocalAuthor a : localAuthors)
|
||||||
adapter.add(new LocalAuthorItem(a));
|
adapter.add(new LocalAuthorItem(a));
|
||||||
adapter.sort(LocalAuthorItemComparator.INSTANCE);
|
adapter.sort(LocalAuthorItemComparator.INSTANCE);
|
||||||
adapter.notifyDataSetChanged();
|
adapter.notifyDataSetChanged();
|
||||||
int count = adapter.getCount();
|
int count = adapter.getCount();
|
||||||
for(int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
LocalAuthorItem item = adapter.getItem(i);
|
LocalAuthorItem item = adapter.getItem(i);
|
||||||
if(item == LocalAuthorItem.ANONYMOUS) continue;
|
if (item == LocalAuthorItem.ANONYMOUS) continue;
|
||||||
if(item == LocalAuthorItem.NEW) continue;
|
if (item == LocalAuthorItem.NEW) continue;
|
||||||
if(item.getLocalAuthor().getId().equals(localAuthorId)) {
|
if (item.getLocalAuthor().getId().equals(localAuthorId)) {
|
||||||
localAuthor = item.getLocalAuthor();
|
localAuthor = item.getLocalAuthor();
|
||||||
spinner.setSelection(i);
|
spinner.setSelection(i);
|
||||||
break;
|
break;
|
||||||
@@ -210,7 +210,7 @@ implements OnItemSelectedListener, OnClickListener {
|
|||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState(Bundle state) {
|
public void onSaveInstanceState(Bundle state) {
|
||||||
super.onSaveInstanceState(state);
|
super.onSaveInstanceState(state);
|
||||||
if(localAuthorId != null) {
|
if (localAuthorId != null) {
|
||||||
byte[] b = localAuthorId.getBytes();
|
byte[] b = localAuthorId.getBytes();
|
||||||
state.putByteArray("briar.LOCAL_AUTHOR_ID", b);
|
state.putByteArray("briar.LOCAL_AUTHOR_ID", b);
|
||||||
}
|
}
|
||||||
@@ -219,9 +219,9 @@ implements OnItemSelectedListener, OnClickListener {
|
|||||||
@Override
|
@Override
|
||||||
protected void onActivityResult(int request, int result, Intent data) {
|
protected void onActivityResult(int request, int result, Intent data) {
|
||||||
super.onActivityResult(request, result, data);
|
super.onActivityResult(request, result, data);
|
||||||
if(request == REQUEST_CREATE_IDENTITY && result == RESULT_OK) {
|
if (request == REQUEST_CREATE_IDENTITY && result == RESULT_OK) {
|
||||||
byte[] b = data.getByteArrayExtra("briar.LOCAL_AUTHOR_ID");
|
byte[] b = data.getByteArrayExtra("briar.LOCAL_AUTHOR_ID");
|
||||||
if(b == null) throw new IllegalStateException();
|
if (b == null) throw new IllegalStateException();
|
||||||
localAuthorId = new AuthorId(b);
|
localAuthorId = new AuthorId(b);
|
||||||
loadAuthorsAndGroup();
|
loadAuthorsAndGroup();
|
||||||
}
|
}
|
||||||
@@ -230,10 +230,10 @@ implements OnItemSelectedListener, OnClickListener {
|
|||||||
public void onItemSelected(AdapterView<?> parent, View view, int position,
|
public void onItemSelected(AdapterView<?> parent, View view, int position,
|
||||||
long id) {
|
long id) {
|
||||||
LocalAuthorItem item = adapter.getItem(position);
|
LocalAuthorItem item = adapter.getItem(position);
|
||||||
if(item == LocalAuthorItem.ANONYMOUS) {
|
if (item == LocalAuthorItem.ANONYMOUS) {
|
||||||
localAuthor = null;
|
localAuthor = null;
|
||||||
localAuthorId = null;
|
localAuthorId = null;
|
||||||
} else if(item == LocalAuthorItem.NEW) {
|
} else if (item == LocalAuthorItem.NEW) {
|
||||||
localAuthor = null;
|
localAuthor = null;
|
||||||
localAuthorId = null;
|
localAuthorId = null;
|
||||||
Intent i = new Intent(this, CreateIdentityActivity.class);
|
Intent i = new Intent(this, CreateIdentityActivity.class);
|
||||||
@@ -250,9 +250,9 @@ implements OnItemSelectedListener, OnClickListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
if(group == null) throw new IllegalStateException();
|
if (group == null) throw new IllegalStateException();
|
||||||
String message = content.getText().toString();
|
String message = content.getText().toString();
|
||||||
if(message.equals("")) return;
|
if (message.equals("")) return;
|
||||||
createMessage(StringUtils.toUtf8(message));
|
createMessage(StringUtils.toUtf8(message));
|
||||||
Toast.makeText(this, R.string.post_sent_toast, LENGTH_LONG).show();
|
Toast.makeText(this, R.string.post_sent_toast, LENGTH_LONG).show();
|
||||||
finish();
|
finish();
|
||||||
@@ -266,7 +266,7 @@ implements OnItemSelectedListener, OnClickListener {
|
|||||||
timestamp = Math.max(timestamp, minTimestamp);
|
timestamp = Math.max(timestamp, minTimestamp);
|
||||||
Message m;
|
Message m;
|
||||||
try {
|
try {
|
||||||
if(localAuthor == null) {
|
if (localAuthor == null) {
|
||||||
m = messageFactory.createAnonymousMessage(parentId,
|
m = messageFactory.createAnonymousMessage(parentId,
|
||||||
group, "text/plain", timestamp, body);
|
group, "text/plain", timestamp, body);
|
||||||
} else {
|
} else {
|
||||||
@@ -277,9 +277,9 @@ implements OnItemSelectedListener, OnClickListener {
|
|||||||
group, localAuthor, authorKey, "text/plain",
|
group, localAuthor, authorKey, "text/plain",
|
||||||
timestamp, body);
|
timestamp, body);
|
||||||
}
|
}
|
||||||
} catch(GeneralSecurityException e) {
|
} catch (GeneralSecurityException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
storeMessage(m);
|
storeMessage(m);
|
||||||
@@ -294,10 +294,10 @@ implements OnItemSelectedListener, OnClickListener {
|
|||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
db.addLocalMessage(m);
|
db.addLocalMessage(m);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Storing message took " + duration + " ms");
|
LOG.info("Storing message took " + duration + " ms");
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ implements OnEditorActionListener, OnClickListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void enableOrDisableCreateButton() {
|
private void enableOrDisableCreateButton() {
|
||||||
if(progress == null) return; // Not created yet
|
if (progress == null) return; // Not created yet
|
||||||
createIdentityButton.setEnabled(validateNickname());
|
createIdentityButton.setEnabled(validateNickname());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ implements OnEditorActionListener, OnClickListener {
|
|||||||
private boolean validateNickname() {
|
private boolean validateNickname() {
|
||||||
String nickname = nicknameEntry.getText().toString();
|
String nickname = nicknameEntry.getText().toString();
|
||||||
int length = StringUtils.toUtf8(nickname).length;
|
int length = StringUtils.toUtf8(nickname).length;
|
||||||
if(length > MAX_AUTHOR_NAME_LENGTH) {
|
if (length > MAX_AUTHOR_NAME_LENGTH) {
|
||||||
feedback.setText(R.string.name_too_long);
|
feedback.setText(R.string.name_too_long);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -135,7 +135,7 @@ implements OnEditorActionListener, OnClickListener {
|
|||||||
|
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
hideSoftKeyboard();
|
hideSoftKeyboard();
|
||||||
if(!validateNickname()) return;
|
if (!validateNickname()) return;
|
||||||
// Replace the button with a progress bar
|
// Replace the button with a progress bar
|
||||||
createIdentityButton.setVisibility(GONE);
|
createIdentityButton.setVisibility(GONE);
|
||||||
progress.setVisibility(VISIBLE);
|
progress.setVisibility(VISIBLE);
|
||||||
@@ -160,10 +160,10 @@ implements OnEditorActionListener, OnClickListener {
|
|||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
db.addLocalAuthor(a);
|
db.addLocalAuthor(a);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Storing author took " + duration + " ms");
|
LOG.info("Storing author took " + duration + " ms");
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
setResultAndFinish(a);
|
setResultAndFinish(a);
|
||||||
|
|||||||
@@ -11,18 +11,18 @@ public class LocalAuthorItemComparator implements Comparator<LocalAuthorItem> {
|
|||||||
new LocalAuthorItemComparator();
|
new LocalAuthorItemComparator();
|
||||||
|
|
||||||
public int compare(LocalAuthorItem a, LocalAuthorItem b) {
|
public int compare(LocalAuthorItem a, LocalAuthorItem b) {
|
||||||
if(a == b) return 0;
|
if (a == b) return 0;
|
||||||
// NEW comes after everything else
|
// NEW comes after everything else
|
||||||
if(a == NEW) return 1;
|
if (a == NEW) return 1;
|
||||||
if(b == NEW) return -1;
|
if (b == NEW) return -1;
|
||||||
// ANONYMOUS comes after everything else except NEW
|
// ANONYMOUS comes after everything else except NEW
|
||||||
if(a == ANONYMOUS) return 1;
|
if (a == ANONYMOUS) return 1;
|
||||||
if(b == ANONYMOUS) return -1;
|
if (b == ANONYMOUS) return -1;
|
||||||
// Sort items in order of creation, so the oldest item is the default
|
// Sort items in order of creation, so the oldest item is the default
|
||||||
long aCreated = a.getLocalAuthor().getTimeCreated();
|
long aCreated = a.getLocalAuthor().getTimeCreated();
|
||||||
long bCreated = b.getLocalAuthor().getTimeCreated();
|
long bCreated = b.getLocalAuthor().getTimeCreated();
|
||||||
if(aCreated < bCreated) return -1;
|
if (aCreated < bCreated) return -1;
|
||||||
if(aCreated > bCreated) return 1;
|
if (aCreated > bCreated) return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ implements SpinnerAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
if(list.isEmpty()) return 0;
|
if (list.isEmpty()) return 0;
|
||||||
return includeAnonymous ? list.size() + 2 : list.size() + 1;
|
return includeAnonymous ? list.size() + 2 : list.size() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,19 +54,19 @@ implements SpinnerAdapter {
|
|||||||
int pad = LayoutUtils.getPadding(ctx);
|
int pad = LayoutUtils.getPadding(ctx);
|
||||||
name.setPadding(pad, pad, pad, pad);
|
name.setPadding(pad, pad, pad, pad);
|
||||||
LocalAuthorItem item = getItem(position);
|
LocalAuthorItem item = getItem(position);
|
||||||
if(item == ANONYMOUS) name.setText(R.string.anonymous);
|
if (item == ANONYMOUS) name.setText(R.string.anonymous);
|
||||||
else if(item == NEW) name.setText(R.string.new_identity_item);
|
else if (item == NEW) name.setText(R.string.new_identity_item);
|
||||||
else name.setText(item.getLocalAuthor().getName());
|
else name.setText(item.getLocalAuthor().getName());
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LocalAuthorItem getItem(int position) {
|
public LocalAuthorItem getItem(int position) {
|
||||||
if(includeAnonymous) {
|
if (includeAnonymous) {
|
||||||
if(position == list.size()) return ANONYMOUS;
|
if (position == list.size()) return ANONYMOUS;
|
||||||
if(position == list.size() + 1) return NEW;
|
if (position == list.size() + 1) return NEW;
|
||||||
return list.get(position);
|
return list.get(position);
|
||||||
} else {
|
} else {
|
||||||
if(position == list.size()) return NEW;
|
if (position == list.size()) return NEW;
|
||||||
return list.get(position);
|
return list.get(position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,8 +81,8 @@ implements SpinnerAdapter {
|
|||||||
name.setSingleLine();
|
name.setSingleLine();
|
||||||
name.setEllipsize(END);
|
name.setEllipsize(END);
|
||||||
LocalAuthorItem item = getItem(position);
|
LocalAuthorItem item = getItem(position);
|
||||||
if(item == ANONYMOUS) name.setText(R.string.anonymous);
|
if (item == ANONYMOUS) name.setText(R.string.anonymous);
|
||||||
else if(item == NEW) name.setText(R.string.new_identity_item);
|
else if (item == NEW) name.setText(R.string.new_identity_item);
|
||||||
else name.setText(item.getLocalAuthor().getName());
|
else name.setText(item.getLocalAuthor().getName());
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,34 +60,34 @@ implements InvitationListener {
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle state) {
|
public void onCreate(Bundle state) {
|
||||||
super.onCreate(state);
|
super.onCreate(state);
|
||||||
if(state == null) {
|
if (state == null) {
|
||||||
// This is a new activity
|
// This is a new activity
|
||||||
setView(new ChooseIdentityView(this));
|
setView(new ChooseIdentityView(this));
|
||||||
} else {
|
} else {
|
||||||
// Restore the activity's state
|
// Restore the activity's state
|
||||||
byte[] b = state.getByteArray("briar.LOCAL_AUTHOR_ID");
|
byte[] b = state.getByteArray("briar.LOCAL_AUTHOR_ID");
|
||||||
if(b != null) localAuthorId = new AuthorId(b);
|
if (b != null) localAuthorId = new AuthorId(b);
|
||||||
taskHandle = state.getLong("briar.TASK_HANDLE", -1);
|
taskHandle = state.getLong("briar.TASK_HANDLE", -1);
|
||||||
task = referenceManager.getReference(taskHandle,
|
task = referenceManager.getReference(taskHandle,
|
||||||
InvitationTask.class);
|
InvitationTask.class);
|
||||||
if(task == null) {
|
if (task == null) {
|
||||||
// No background task - we must be in an initial or final state
|
// No background task - we must be in an initial or final state
|
||||||
localInvitationCode = state.getInt("briar.LOCAL_CODE");
|
localInvitationCode = state.getInt("briar.LOCAL_CODE");
|
||||||
remoteInvitationCode = state.getInt("briar.REMOTE_CODE");
|
remoteInvitationCode = state.getInt("briar.REMOTE_CODE");
|
||||||
connectionFailed = state.getBoolean("briar.FAILED");
|
connectionFailed = state.getBoolean("briar.FAILED");
|
||||||
contactName = state.getString("briar.CONTACT_NAME");
|
contactName = state.getString("briar.CONTACT_NAME");
|
||||||
if(contactName != null) {
|
if (contactName != null) {
|
||||||
localCompared = remoteCompared = true;
|
localCompared = remoteCompared = true;
|
||||||
localMatched = remoteMatched = true;
|
localMatched = remoteMatched = true;
|
||||||
}
|
}
|
||||||
// Set the appropriate view for the state
|
// Set the appropriate view for the state
|
||||||
if(localInvitationCode == -1) {
|
if (localInvitationCode == -1) {
|
||||||
setView(new ChooseIdentityView(this));
|
setView(new ChooseIdentityView(this));
|
||||||
} else if(remoteInvitationCode == -1) {
|
} else if (remoteInvitationCode == -1) {
|
||||||
setView(new InvitationCodeView(this));
|
setView(new InvitationCodeView(this));
|
||||||
} else if(connectionFailed) {
|
} else if (connectionFailed) {
|
||||||
setView(new ConnectionFailedView(this));
|
setView(new ConnectionFailedView(this));
|
||||||
} else if(contactName == null) {
|
} else if (contactName == null) {
|
||||||
setView(new CodesDoNotMatchView(this));
|
setView(new CodesDoNotMatchView(this));
|
||||||
} else {
|
} else {
|
||||||
showToastAndFinish();
|
showToastAndFinish();
|
||||||
@@ -108,22 +108,22 @@ implements InvitationListener {
|
|||||||
remoteMatched = s.getRemoteMatched();
|
remoteMatched = s.getRemoteMatched();
|
||||||
contactName = s.getContactName();
|
contactName = s.getContactName();
|
||||||
// Set the appropriate view for the state
|
// Set the appropriate view for the state
|
||||||
if(localInvitationCode == -1) {
|
if (localInvitationCode == -1) {
|
||||||
setView(new ChooseIdentityView(this));
|
setView(new ChooseIdentityView(this));
|
||||||
} else if(remoteInvitationCode == -1) {
|
} else if (remoteInvitationCode == -1) {
|
||||||
setView(new InvitationCodeView(this));
|
setView(new InvitationCodeView(this));
|
||||||
} else if(connectionFailed) {
|
} else if (connectionFailed) {
|
||||||
setView(new ConnectionFailedView(this));
|
setView(new ConnectionFailedView(this));
|
||||||
} else if(connected && localConfirmationCode == -1) {
|
} else if (connected && localConfirmationCode == -1) {
|
||||||
setView(new ConnectedView(this));
|
setView(new ConnectedView(this));
|
||||||
} else if(localConfirmationCode == -1) {
|
} else if (localConfirmationCode == -1) {
|
||||||
setView(new ConnectionView(this));
|
setView(new ConnectionView(this));
|
||||||
} else if(!localCompared) {
|
} else if (!localCompared) {
|
||||||
setView(new ConfirmationCodeView(this));
|
setView(new ConfirmationCodeView(this));
|
||||||
} else if(!remoteCompared) {
|
} else if (!remoteCompared) {
|
||||||
setView(new WaitForContactView(this));
|
setView(new WaitForContactView(this));
|
||||||
} else if(localMatched && remoteMatched) {
|
} else if (localMatched && remoteMatched) {
|
||||||
if(contactName == null) {
|
if (contactName == null) {
|
||||||
setView(new ContactDetailsView(this));
|
setView(new ContactDetailsView(this));
|
||||||
} else {
|
} else {
|
||||||
showToastAndFinish();
|
showToastAndFinish();
|
||||||
@@ -135,7 +135,7 @@ implements InvitationListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||||
if(adapter != null) bluetoothWasEnabled = adapter.isEnabled();
|
if (adapter != null) bluetoothWasEnabled = adapter.isEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showToastAndFinish() {
|
private void showToastAndFinish() {
|
||||||
@@ -159,11 +159,11 @@ implements InvitationListener {
|
|||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
TransportConfig c = db.getConfig(new TransportId("bt"));
|
TransportConfig c = db.getConfig(new TransportId("bt"));
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Loading setting took " + duration + " ms");
|
LOG.info("Loading setting took " + duration + " ms");
|
||||||
enableBluetooth = c.getBoolean("enable", true);
|
enableBluetooth = c.getBoolean("enable", true);
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,7 +173,7 @@ implements InvitationListener {
|
|||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState(Bundle state) {
|
public void onSaveInstanceState(Bundle state) {
|
||||||
super.onSaveInstanceState(state);
|
super.onSaveInstanceState(state);
|
||||||
if(localAuthorId != null) {
|
if (localAuthorId != null) {
|
||||||
byte[] b = localAuthorId.getBytes();
|
byte[] b = localAuthorId.getBytes();
|
||||||
state.putByteArray("briar.LOCAL_AUTHOR_ID", b);
|
state.putByteArray("briar.LOCAL_AUTHOR_ID", b);
|
||||||
}
|
}
|
||||||
@@ -181,26 +181,26 @@ implements InvitationListener {
|
|||||||
state.putInt("briar.REMOTE_CODE", remoteInvitationCode);
|
state.putInt("briar.REMOTE_CODE", remoteInvitationCode);
|
||||||
state.putBoolean("briar.FAILED", connectionFailed);
|
state.putBoolean("briar.FAILED", connectionFailed);
|
||||||
state.putString("briar.CONTACT_NAME", contactName);
|
state.putString("briar.CONTACT_NAME", contactName);
|
||||||
if(task != null) state.putLong("briar.TASK_HANDLE", taskHandle);
|
if (task != null) state.putLong("briar.TASK_HANDLE", taskHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
if(task != null) task.removeListener(this);
|
if (task != null) task.removeListener(this);
|
||||||
if(!bluetoothWasEnabled && !enableBluetooth) {
|
if (!bluetoothWasEnabled && !enableBluetooth) {
|
||||||
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||||
if(adapter != null) adapter.disable();
|
if (adapter != null) adapter.disable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResult(int request, int result, Intent data) {
|
public void onActivityResult(int request, int result, Intent data) {
|
||||||
if(request == REQUEST_BLUETOOTH) {
|
if (request == REQUEST_BLUETOOTH) {
|
||||||
if(result != RESULT_CANCELED) reset(new InvitationCodeView(this));
|
if (result != RESULT_CANCELED) reset(new InvitationCodeView(this));
|
||||||
} else if(request == REQUEST_CREATE_IDENTITY && result == RESULT_OK) {
|
} else if (request == REQUEST_CREATE_IDENTITY && result == RESULT_OK) {
|
||||||
byte[] b = data.getByteArrayExtra("briar.LOCAL_AUTHOR_ID");
|
byte[] b = data.getByteArrayExtra("briar.LOCAL_AUTHOR_ID");
|
||||||
if(b == null) throw new IllegalStateException();
|
if (b == null) throw new IllegalStateException();
|
||||||
localAuthorId = new AuthorId(b);
|
localAuthorId = new AuthorId(b);
|
||||||
setView(new ChooseIdentityView(this));
|
setView(new ChooseIdentityView(this));
|
||||||
}
|
}
|
||||||
@@ -232,11 +232,11 @@ implements InvitationListener {
|
|||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
Collection<LocalAuthor> authors = db.getLocalAuthors();
|
Collection<LocalAuthor> authors = db.getLocalAuthors();
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Loading authors took " + duration + " ms");
|
LOG.info("Loading authors took " + duration + " ms");
|
||||||
displayLocalAuthors(authors);
|
displayLocalAuthors(authors);
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -248,7 +248,7 @@ implements InvitationListener {
|
|||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
AddContactView view = AddContactActivity.this.view;
|
AddContactView view = AddContactActivity.this.view;
|
||||||
if(view instanceof ChooseIdentityView)
|
if (view instanceof ChooseIdentityView)
|
||||||
((ChooseIdentityView) view).displayLocalAuthors(authors);
|
((ChooseIdentityView) view).displayLocalAuthors(authors);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -263,7 +263,7 @@ implements InvitationListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int getLocalInvitationCode() {
|
int getLocalInvitationCode() {
|
||||||
if(localInvitationCode == -1)
|
if (localInvitationCode == -1)
|
||||||
localInvitationCode = crypto.generateInvitationCode();
|
localInvitationCode = crypto.generateInvitationCode();
|
||||||
return localInvitationCode;
|
return localInvitationCode;
|
||||||
}
|
}
|
||||||
@@ -273,8 +273,8 @@ implements InvitationListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void remoteInvitationCodeEntered(int code) {
|
void remoteInvitationCodeEntered(int code) {
|
||||||
if(localAuthorId == null) throw new IllegalStateException();
|
if (localAuthorId == null) throw new IllegalStateException();
|
||||||
if(localInvitationCode == -1) throw new IllegalStateException();
|
if (localInvitationCode == -1) throw new IllegalStateException();
|
||||||
remoteInvitationCode = code;
|
remoteInvitationCode = code;
|
||||||
setView(new ConnectionView(this));
|
setView(new ConnectionView(this));
|
||||||
task = invitationTaskFactory.createTask(localAuthorId,
|
task = invitationTaskFactory.createTask(localAuthorId,
|
||||||
@@ -293,10 +293,10 @@ implements InvitationListener {
|
|||||||
|
|
||||||
void remoteConfirmationCodeEntered(int code) {
|
void remoteConfirmationCodeEntered(int code) {
|
||||||
localCompared = true;
|
localCompared = true;
|
||||||
if(code == remoteConfirmationCode) {
|
if (code == remoteConfirmationCode) {
|
||||||
localMatched = true;
|
localMatched = true;
|
||||||
if(remoteMatched) setView(new ContactDetailsView(this));
|
if (remoteMatched) setView(new ContactDetailsView(this));
|
||||||
else if(remoteCompared) setView(new CodesDoNotMatchView(this));
|
else if (remoteCompared) setView(new CodesDoNotMatchView(this));
|
||||||
else setView(new WaitForContactView(this));
|
else setView(new WaitForContactView(this));
|
||||||
task.localConfirmationSucceeded();
|
task.localConfirmationSucceeded();
|
||||||
} else {
|
} else {
|
||||||
@@ -353,7 +353,7 @@ implements InvitationListener {
|
|||||||
public void run() {
|
public void run() {
|
||||||
remoteCompared = true;
|
remoteCompared = true;
|
||||||
remoteMatched = true;
|
remoteMatched = true;
|
||||||
if(localMatched)
|
if (localMatched)
|
||||||
setView(new ContactDetailsView(AddContactActivity.this));
|
setView(new ContactDetailsView(AddContactActivity.this));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -364,7 +364,7 @@ implements InvitationListener {
|
|||||||
public void run() {
|
public void run() {
|
||||||
remoteCompared = true;
|
remoteCompared = true;
|
||||||
remoteMatched = false;
|
remoteMatched = false;
|
||||||
if(localMatched)
|
if (localMatched)
|
||||||
setView(new CodesDoNotMatchView(AddContactActivity.this));
|
setView(new CodesDoNotMatchView(AddContactActivity.this));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -80,17 +80,17 @@ implements OnItemSelectedListener, OnClickListener {
|
|||||||
// FIXME: The interaction between views and the container is horrible
|
// FIXME: The interaction between views and the container is horrible
|
||||||
void displayLocalAuthors(Collection<LocalAuthor> authors) {
|
void displayLocalAuthors(Collection<LocalAuthor> authors) {
|
||||||
adapter.clear();
|
adapter.clear();
|
||||||
for(LocalAuthor a : authors) adapter.add(new LocalAuthorItem(a));
|
for (LocalAuthor a : authors) adapter.add(new LocalAuthorItem(a));
|
||||||
adapter.sort(LocalAuthorItemComparator.INSTANCE);
|
adapter.sort(LocalAuthorItemComparator.INSTANCE);
|
||||||
adapter.notifyDataSetChanged();
|
adapter.notifyDataSetChanged();
|
||||||
// If a local author has been selected, select it again
|
// If a local author has been selected, select it again
|
||||||
AuthorId localAuthorId = container.getLocalAuthorId();
|
AuthorId localAuthorId = container.getLocalAuthorId();
|
||||||
if(localAuthorId == null) return;
|
if (localAuthorId == null) return;
|
||||||
int count = adapter.getCount();
|
int count = adapter.getCount();
|
||||||
for(int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
LocalAuthorItem item = adapter.getItem(i);
|
LocalAuthorItem item = adapter.getItem(i);
|
||||||
if(item == NEW) continue;
|
if (item == NEW) continue;
|
||||||
if(item.getLocalAuthor().getId().equals(localAuthorId)) {
|
if (item.getLocalAuthor().getId().equals(localAuthorId)) {
|
||||||
spinner.setSelection(i);
|
spinner.setSelection(i);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -100,7 +100,7 @@ implements OnItemSelectedListener, OnClickListener {
|
|||||||
public void onItemSelected(AdapterView<?> parent, View view, int position,
|
public void onItemSelected(AdapterView<?> parent, View view, int position,
|
||||||
long id) {
|
long id) {
|
||||||
LocalAuthorItem item = adapter.getItem(position);
|
LocalAuthorItem item = adapter.getItem(position);
|
||||||
if(item == NEW) {
|
if (item == NEW) {
|
||||||
container.setLocalAuthorId(null);
|
container.setLocalAuthorId(null);
|
||||||
Intent i = new Intent(container, CreateIdentityActivity.class);
|
Intent i = new Intent(container, CreateIdentityActivity.class);
|
||||||
container.startActivityForResult(i, REQUEST_CREATE_IDENTITY);
|
container.startActivityForResult(i, REQUEST_CREATE_IDENTITY);
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ implements OnEditorActionListener, OnClickListener {
|
|||||||
@Override
|
@Override
|
||||||
protected void onTextChanged(CharSequence text, int start,
|
protected void onTextChanged(CharSequence text, int start,
|
||||||
int lengthBefore, int lengthAfter) {
|
int lengthBefore, int lengthAfter) {
|
||||||
if(continueButton != null)
|
if (continueButton != null)
|
||||||
continueButton.setEnabled(getText().length() == 6);
|
continueButton.setEnabled(getText().length() == 6);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -78,12 +78,12 @@ implements OnEditorActionListener, OnClickListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean onEditorAction(TextView textView, int actionId, KeyEvent e) {
|
public boolean onEditorAction(TextView textView, int actionId, KeyEvent e) {
|
||||||
if(!validateAndReturnCode()) codeEntry.setText("");
|
if (!validateAndReturnCode()) codeEntry.setText("");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
if(!validateAndReturnCode()) codeEntry.setText("");
|
if (!validateAndReturnCode()) codeEntry.setText("");
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean validateAndReturnCode() {
|
private boolean validateAndReturnCode() {
|
||||||
@@ -91,7 +91,7 @@ implements OnEditorActionListener, OnClickListener {
|
|||||||
int remoteCode;
|
int remoteCode;
|
||||||
try {
|
try {
|
||||||
remoteCode = Integer.parseInt(remoteCodeString);
|
remoteCode = Integer.parseInt(remoteCodeString);
|
||||||
} catch(NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Hide the soft keyboard
|
// Hide the soft keyboard
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ public class AndroidUtils {
|
|||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public static Collection<String> getSupportedArchitectures() {
|
public static Collection<String> getSupportedArchitectures() {
|
||||||
List<String> abis = new ArrayList<String>();
|
List<String> abis = new ArrayList<String>();
|
||||||
if(Build.VERSION.SDK_INT >= 21) {
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
for(String abi : Build.SUPPORTED_ABIS) abis.add(abi);
|
for (String abi : Build.SUPPORTED_ABIS) abis.add(abi);
|
||||||
} else if(Build.VERSION.SDK_INT >= 8) {
|
} else if (Build.VERSION.SDK_INT >= 8) {
|
||||||
abis.add(Build.CPU_ABI);
|
abis.add(Build.CPU_ABI);
|
||||||
if(Build.CPU_ABI2 != null) abis.add(Build.CPU_ABI2);
|
if (Build.CPU_ABI2 != null) abis.add(Build.CPU_ABI2);
|
||||||
} else {
|
} else {
|
||||||
abis.add(Build.CPU_ABI);
|
abis.add(Build.CPU_ABI);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ public class AuthorView extends RelativeLayout {
|
|||||||
nameView.setSingleLine();
|
nameView.setSingleLine();
|
||||||
nameView.setEllipsize(END);
|
nameView.setEllipsize(END);
|
||||||
nameView.setPadding(pad, pad, pad, pad);
|
nameView.setPadding(pad, pad, pad, pad);
|
||||||
if(name == null) nameView.setText(R.string.anonymous);
|
if (name == null) nameView.setText(R.string.anonymous);
|
||||||
else nameView.setText(name);
|
else nameView.setText(name);
|
||||||
LayoutParams leftOf = CommonLayoutParams.relative();
|
LayoutParams leftOf = CommonLayoutParams.relative();
|
||||||
leftOf.addRule(ALIGN_PARENT_LEFT);
|
leftOf.addRule(ALIGN_PARENT_LEFT);
|
||||||
|
|||||||
@@ -52,12 +52,12 @@ public class StrengthMeter extends ProgressBar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setStrength(float strength) {
|
public void setStrength(float strength) {
|
||||||
if(strength < 0 || strength > 1) throw new IllegalArgumentException();
|
if (strength < 0 || strength > 1) throw new IllegalArgumentException();
|
||||||
int colour;
|
int colour;
|
||||||
if(strength < WEAK) colour = RED;
|
if (strength < WEAK) colour = RED;
|
||||||
else if(strength < QUITE_WEAK) colour = ORANGE;
|
else if (strength < QUITE_WEAK) colour = ORANGE;
|
||||||
else if(strength < QUITE_STRONG) colour = YELLOW;
|
else if (strength < QUITE_STRONG) colour = YELLOW;
|
||||||
else if(strength < STRONG) colour = LIME;
|
else if (strength < STRONG) colour = LIME;
|
||||||
else colour = GREEN;
|
else colour = GREEN;
|
||||||
bar.getPaint().setColor(colour);
|
bar.getPaint().setColor(colour);
|
||||||
setProgress((int) (strength * MAX));
|
setProgress((int) (strength * MAX));
|
||||||
|
|||||||
@@ -115,13 +115,13 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
return BluetoothAdapter.getDefaultAdapter();
|
return BluetoothAdapter.getDefaultAdapter();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch(InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
throw new IOException("Interrupted while getting BluetoothAdapter");
|
throw new IOException("Interrupted while getting BluetoothAdapter");
|
||||||
} catch(ExecutionException e) {
|
} catch (ExecutionException e) {
|
||||||
throw new IOException(e.toString());
|
throw new IOException(e.toString());
|
||||||
}
|
}
|
||||||
if(adapter == null) {
|
if (adapter == null) {
|
||||||
LOG.info("Bluetooth is not supported");
|
LOG.info("Bluetooth is not supported");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -133,11 +133,11 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
receiver = new BluetoothStateReceiver();
|
receiver = new BluetoothStateReceiver();
|
||||||
appContext.registerReceiver(receiver, filter);
|
appContext.registerReceiver(receiver, filter);
|
||||||
// If Bluetooth is enabled, bind a socket - otherwise enable it
|
// If Bluetooth is enabled, bind a socket - otherwise enable it
|
||||||
if(adapter.isEnabled()) {
|
if (adapter.isEnabled()) {
|
||||||
bind();
|
bind();
|
||||||
} else if(callback.getConfig().getBoolean("enable", true)) {
|
} else if (callback.getConfig().getBoolean("enable", true)) {
|
||||||
wasDisabled = true;
|
wasDisabled = true;
|
||||||
if(adapter.enable()) LOG.info("Enabling Bluetooth");
|
if (adapter.enable()) LOG.info("Enabling Bluetooth");
|
||||||
else LOG.info("Could not enable Bluetooth");
|
else LOG.info("Could not enable Bluetooth");
|
||||||
} else {
|
} else {
|
||||||
LOG.info("Not enabling Bluetooth");
|
LOG.info("Not enabling Bluetooth");
|
||||||
@@ -148,8 +148,8 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
private void bind() {
|
private void bind() {
|
||||||
ioExecutor.execute(new Runnable() {
|
ioExecutor.execute(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
if(!isRunning()) return;
|
if (!isRunning()) return;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Local address " + adapter.getAddress());
|
LOG.info("Local address " + adapter.getAddress());
|
||||||
// Advertise the Bluetooth address to contacts
|
// Advertise the Bluetooth address to contacts
|
||||||
TransportProperties p = new TransportProperties();
|
TransportProperties p = new TransportProperties();
|
||||||
@@ -159,13 +159,13 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
BluetoothServerSocket ss = null;
|
BluetoothServerSocket ss = null;
|
||||||
try {
|
try {
|
||||||
ss = InsecureBluetooth.listen(adapter, "RFCOMM", getUuid());
|
ss = InsecureBluetooth.listen(adapter, "RFCOMM", getUuid());
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
tryToClose(ss);
|
tryToClose(ss);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(!isRunning()) {
|
if (!isRunning()) {
|
||||||
tryToClose(ss);
|
tryToClose(ss);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -179,7 +179,7 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
|
|
||||||
private UUID getUuid() {
|
private UUID getUuid() {
|
||||||
String uuid = callback.getLocalProperties().get("uuid");
|
String uuid = callback.getLocalProperties().get("uuid");
|
||||||
if(uuid == null) {
|
if (uuid == null) {
|
||||||
byte[] random = new byte[UUID_BYTES];
|
byte[] random = new byte[UUID_BYTES];
|
||||||
secureRandom.nextBytes(random);
|
secureRandom.nextBytes(random);
|
||||||
uuid = UUID.nameUUIDFromBytes(random).toString();
|
uuid = UUID.nameUUIDFromBytes(random).toString();
|
||||||
@@ -192,23 +192,23 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
|
|
||||||
private void tryToClose(BluetoothServerSocket ss) {
|
private void tryToClose(BluetoothServerSocket ss) {
|
||||||
try {
|
try {
|
||||||
if(ss != null) ss.close();
|
if (ss != null) ss.close();
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void acceptContactConnections() {
|
private void acceptContactConnections() {
|
||||||
while(isRunning()) {
|
while (isRunning()) {
|
||||||
BluetoothSocket s;
|
BluetoothSocket s;
|
||||||
try {
|
try {
|
||||||
s = socket.accept();
|
s = socket.accept();
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
// This is expected when the socket is closed
|
// This is expected when the socket is closed
|
||||||
if(LOG.isLoggable(INFO)) LOG.info(e.toString());
|
if (LOG.isLoggable(INFO)) LOG.info(e.toString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
String address = s.getRemoteDevice().getAddress();
|
String address = s.getRemoteDevice().getAddress();
|
||||||
LOG.info("Connection from " + address);
|
LOG.info("Connection from " + address);
|
||||||
}
|
}
|
||||||
@@ -222,11 +222,11 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
running = false;
|
running = false;
|
||||||
if(receiver != null) appContext.unregisterReceiver(receiver);
|
if (receiver != null) appContext.unregisterReceiver(receiver);
|
||||||
tryToClose(socket);
|
tryToClose(socket);
|
||||||
// Disable Bluetooth if we enabled it and it's still enabled
|
// Disable Bluetooth if we enabled it and it's still enabled
|
||||||
if(wasDisabled && adapter.isEnabled()) {
|
if (wasDisabled && adapter.isEnabled()) {
|
||||||
if(adapter.disable()) LOG.info("Disabling Bluetooth");
|
if (adapter.disable()) LOG.info("Disabling Bluetooth");
|
||||||
else LOG.info("Could not disable Bluetooth");
|
else LOG.info("Could not disable Bluetooth");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -244,22 +244,22 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void poll(Collection<ContactId> connected) {
|
public void poll(Collection<ContactId> connected) {
|
||||||
if(!isRunning()) return;
|
if (!isRunning()) return;
|
||||||
// Try to connect to known devices in parallel
|
// Try to connect to known devices in parallel
|
||||||
Map<ContactId, TransportProperties> remote =
|
Map<ContactId, TransportProperties> remote =
|
||||||
callback.getRemoteProperties();
|
callback.getRemoteProperties();
|
||||||
for(Entry<ContactId, TransportProperties> e : remote.entrySet()) {
|
for (Entry<ContactId, TransportProperties> e : remote.entrySet()) {
|
||||||
final ContactId c = e.getKey();
|
final ContactId c = e.getKey();
|
||||||
if(connected.contains(c)) continue;
|
if (connected.contains(c)) continue;
|
||||||
final String address = e.getValue().get("address");
|
final String address = e.getValue().get("address");
|
||||||
if(StringUtils.isNullOrEmpty(address)) continue;
|
if (StringUtils.isNullOrEmpty(address)) continue;
|
||||||
final String uuid = e.getValue().get("uuid");
|
final String uuid = e.getValue().get("uuid");
|
||||||
if(StringUtils.isNullOrEmpty(uuid)) continue;
|
if (StringUtils.isNullOrEmpty(uuid)) continue;
|
||||||
ioExecutor.execute(new Runnable() {
|
ioExecutor.execute(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
if(!running) return;
|
if (!running) return;
|
||||||
BluetoothSocket s = connect(address, uuid);
|
BluetoothSocket s = connect(address, uuid);
|
||||||
if(s != null)
|
if (s != null)
|
||||||
callback.outgoingConnectionCreated(c, wrapSocket(s));
|
callback.outgoingConnectionCreated(c, wrapSocket(s));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -268,8 +268,8 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
|
|
||||||
private BluetoothSocket connect(String address, String uuid) {
|
private BluetoothSocket connect(String address, String uuid) {
|
||||||
// Validate the address
|
// Validate the address
|
||||||
if(!BluetoothAdapter.checkBluetoothAddress(address)) {
|
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.warning("Invalid address " + address);
|
LOG.warning("Invalid address " + address);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -277,8 +277,8 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
UUID u;
|
UUID u;
|
||||||
try {
|
try {
|
||||||
u = UUID.fromString(uuid);
|
u = UUID.fromString(uuid);
|
||||||
} catch(IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.warning("Invalid UUID " + uuid);
|
if (LOG.isLoggable(WARNING)) LOG.warning("Invalid UUID " + uuid);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// Try to connect
|
// Try to connect
|
||||||
@@ -286,12 +286,12 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
BluetoothSocket s = null;
|
BluetoothSocket s = null;
|
||||||
try {
|
try {
|
||||||
s = InsecureBluetooth.createSocket(d, u);
|
s = InsecureBluetooth.createSocket(d, u);
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("Connecting to " + address);
|
if (LOG.isLoggable(INFO)) LOG.info("Connecting to " + address);
|
||||||
s.connect();
|
s.connect();
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("Connected to " + address);
|
if (LOG.isLoggable(INFO)) LOG.info("Connected to " + address);
|
||||||
return s;
|
return s;
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Failed to connect to " + address);
|
LOG.info("Failed to connect to " + address);
|
||||||
tryToClose(s);
|
tryToClose(s);
|
||||||
return null;
|
return null;
|
||||||
@@ -300,22 +300,22 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
|
|
||||||
private void tryToClose(BluetoothSocket s) {
|
private void tryToClose(BluetoothSocket s) {
|
||||||
try {
|
try {
|
||||||
if(s != null) s.close();
|
if (s != null) s.close();
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DuplexTransportConnection createConnection(ContactId c) {
|
public DuplexTransportConnection createConnection(ContactId c) {
|
||||||
if(!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
TransportProperties p = callback.getRemoteProperties().get(c);
|
TransportProperties p = callback.getRemoteProperties().get(c);
|
||||||
if(p == null) return null;
|
if (p == null) return null;
|
||||||
String address = p.get("address");
|
String address = p.get("address");
|
||||||
if(StringUtils.isNullOrEmpty(address)) return null;
|
if (StringUtils.isNullOrEmpty(address)) return null;
|
||||||
String uuid = p.get("uuid");
|
String uuid = p.get("uuid");
|
||||||
if(StringUtils.isNullOrEmpty(uuid)) return null;
|
if (StringUtils.isNullOrEmpty(uuid)) return null;
|
||||||
BluetoothSocket s = connect(address, uuid);
|
BluetoothSocket s = connect(address, uuid);
|
||||||
if(s == null) return null;
|
if (s == null) return null;
|
||||||
return new DroidtoothTransportConnection(this, s);
|
return new DroidtoothTransportConnection(this, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,17 +325,17 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
|
|
||||||
public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
|
public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
|
||||||
long timeout) {
|
long timeout) {
|
||||||
if(!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
// Use the invitation codes to generate the UUID
|
// Use the invitation codes to generate the UUID
|
||||||
byte[] b = r.nextBytes(UUID_BYTES);
|
byte[] b = r.nextBytes(UUID_BYTES);
|
||||||
UUID uuid = UUID.nameUUIDFromBytes(b);
|
UUID uuid = UUID.nameUUIDFromBytes(b);
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("Invitation UUID " + uuid);
|
if (LOG.isLoggable(INFO)) LOG.info("Invitation UUID " + uuid);
|
||||||
// Bind a server socket for receiving invitation connections
|
// Bind a server socket for receiving invitation connections
|
||||||
BluetoothServerSocket ss = null;
|
BluetoothServerSocket ss = null;
|
||||||
try {
|
try {
|
||||||
ss = InsecureBluetooth.listen(adapter, "RFCOMM", uuid);
|
ss = InsecureBluetooth.listen(adapter, "RFCOMM", uuid);
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
tryToClose(ss);
|
tryToClose(ss);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -347,8 +347,8 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
// Wait for an incoming or outgoing connection
|
// Wait for an incoming or outgoing connection
|
||||||
try {
|
try {
|
||||||
BluetoothSocket s = socketLatch.waitForReference(timeout);
|
BluetoothSocket s = socketLatch.waitForReference(timeout);
|
||||||
if(s != null) return new DroidtoothTransportConnection(this, s);
|
if (s != null) return new DroidtoothTransportConnection(this, s);
|
||||||
} catch(InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.warning("Interrupted while exchanging invitations");
|
LOG.warning("Interrupted while exchanging invitations");
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
} finally {
|
} finally {
|
||||||
@@ -363,19 +363,19 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
@Override
|
@Override
|
||||||
public void onReceive(Context ctx, Intent intent) {
|
public void onReceive(Context ctx, Intent intent) {
|
||||||
int state = intent.getIntExtra(EXTRA_STATE, 0);
|
int state = intent.getIntExtra(EXTRA_STATE, 0);
|
||||||
if(state == STATE_ON) {
|
if (state == STATE_ON) {
|
||||||
LOG.info("Bluetooth enabled");
|
LOG.info("Bluetooth enabled");
|
||||||
bind();
|
bind();
|
||||||
} else if(state == STATE_OFF) {
|
} else if (state == STATE_OFF) {
|
||||||
LOG.info("Bluetooth disabled");
|
LOG.info("Bluetooth disabled");
|
||||||
tryToClose(socket);
|
tryToClose(socket);
|
||||||
}
|
}
|
||||||
int scanMode = intent.getIntExtra(EXTRA_SCAN_MODE, 0);
|
int scanMode = intent.getIntExtra(EXTRA_SCAN_MODE, 0);
|
||||||
if(scanMode == SCAN_MODE_NONE) {
|
if (scanMode == SCAN_MODE_NONE) {
|
||||||
LOG.info("Scan mode: None");
|
LOG.info("Scan mode: None");
|
||||||
} else if(scanMode == SCAN_MODE_CONNECTABLE) {
|
} else if (scanMode == SCAN_MODE_CONNECTABLE) {
|
||||||
LOG.info("Scan mode: Connectable");
|
LOG.info("Scan mode: Connectable");
|
||||||
} else if(scanMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
|
} else if (scanMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
|
||||||
LOG.info("Scan mode: Discoverable");
|
LOG.info("Scan mode: Discoverable");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -397,29 +397,29 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
long end = clock.currentTimeMillis() + timeout;
|
long end = clock.currentTimeMillis() + timeout;
|
||||||
while(!finished(end)) {
|
while (!finished(end)) {
|
||||||
// Discover nearby devices
|
// Discover nearby devices
|
||||||
LOG.info("Discovering nearby devices");
|
LOG.info("Discovering nearby devices");
|
||||||
List<String> addresses;
|
List<String> addresses;
|
||||||
try {
|
try {
|
||||||
long now = clock.currentTimeMillis();
|
long now = clock.currentTimeMillis();
|
||||||
addresses = discoverDevices(end - now);
|
addresses = discoverDevices(end - now);
|
||||||
} catch(InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.warning("Interrupted while discovering devices");
|
LOG.warning("Interrupted while discovering devices");
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(addresses.isEmpty()) {
|
if (addresses.isEmpty()) {
|
||||||
LOG.info("No devices discovered");
|
LOG.info("No devices discovered");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Connect to any device with the right UUID
|
// Connect to any device with the right UUID
|
||||||
for(String address : addresses) {
|
for (String address : addresses) {
|
||||||
if(finished(end)) return;
|
if (finished(end)) return;
|
||||||
BluetoothSocket s = connect(address, uuid);
|
BluetoothSocket s = connect(address, uuid);
|
||||||
if(s != null) {
|
if (s != null) {
|
||||||
LOG.info("Outgoing connection");
|
LOG.info("Outgoing connection");
|
||||||
if(!socketLatch.set(s)) {
|
if (!socketLatch.set(s)) {
|
||||||
LOG.info("Closing redundant connection");
|
LOG.info("Closing redundant connection");
|
||||||
tryToClose(s);
|
tryToClose(s);
|
||||||
}
|
}
|
||||||
@@ -455,13 +455,13 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
@Override
|
@Override
|
||||||
public void onReceive(Context ctx, Intent intent) {
|
public void onReceive(Context ctx, Intent intent) {
|
||||||
String action = intent.getAction();
|
String action = intent.getAction();
|
||||||
if(action.equals(DISCOVERY_FINISHED)) {
|
if (action.equals(DISCOVERY_FINISHED)) {
|
||||||
LOG.info("Discovery finished");
|
LOG.info("Discovery finished");
|
||||||
ctx.unregisterReceiver(this);
|
ctx.unregisterReceiver(this);
|
||||||
finished.countDown();
|
finished.countDown();
|
||||||
} else if(action.equals(FOUND)) {
|
} else if (action.equals(FOUND)) {
|
||||||
BluetoothDevice d = intent.getParcelableExtra(EXTRA_DEVICE);
|
BluetoothDevice d = intent.getParcelableExtra(EXTRA_DEVICE);
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Discovered device: " + d.getAddress());
|
LOG.info("Discovered device: " + d.getAddress());
|
||||||
addresses.add(d.getAddress());
|
addresses.add(d.getAddress());
|
||||||
}
|
}
|
||||||
@@ -491,13 +491,13 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
try {
|
try {
|
||||||
BluetoothSocket s = serverSocket.accept();
|
BluetoothSocket s = serverSocket.accept();
|
||||||
LOG.info("Incoming connection");
|
LOG.info("Incoming connection");
|
||||||
if(!socketLatch.set(s)) {
|
if (!socketLatch.set(s)) {
|
||||||
LOG.info("Closing redundant connection");
|
LOG.info("Closing redundant connection");
|
||||||
s.close();
|
s.close();
|
||||||
}
|
}
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
// This is expected when the socket is closed
|
// This is expected when the socket is closed
|
||||||
if(LOG.isLoggable(INFO)) LOG.info(e.toString());
|
if (LOG.isLoggable(INFO)) LOG.info(e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ class DroidtoothTransportConnection implements DuplexTransportConnection {
|
|||||||
|
|
||||||
public void dispose(boolean exception, boolean recognised)
|
public void dispose(boolean exception, boolean recognised)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if(halfClosed.getAndSet(true) || exception)
|
if (halfClosed.getAndSet(true) || exception)
|
||||||
if(!closed.getAndSet(true)) socket.close();
|
if (!closed.getAndSet(true)) socket.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,8 +73,8 @@ class DroidtoothTransportConnection implements DuplexTransportConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void dispose(boolean exception) throws IOException {
|
public void dispose(boolean exception) throws IOException {
|
||||||
if(halfClosed.getAndSet(true) || exception)
|
if (halfClosed.getAndSet(true) || exception)
|
||||||
if(!closed.getAndSet(true)) socket.close();
|
if (!closed.getAndSet(true)) socket.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class InsecureBluetooth {
|
|||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
static BluetoothServerSocket listen(BluetoothAdapter adapter, String name,
|
static BluetoothServerSocket listen(BluetoothAdapter adapter, String name,
|
||||||
UUID uuid) throws IOException {
|
UUID uuid) throws IOException {
|
||||||
if(Build.VERSION.SDK_INT >= 10) {
|
if (Build.VERSION.SDK_INT >= 10) {
|
||||||
LOG.info("Listening with new API");
|
LOG.info("Listening with new API");
|
||||||
return adapter.listenUsingInsecureRfcommWithServiceRecord(name,
|
return adapter.listenUsingInsecureRfcommWithServiceRecord(name,
|
||||||
uuid);
|
uuid);
|
||||||
@@ -42,13 +42,13 @@ class InsecureBluetooth {
|
|||||||
+ ".RfcommChannelPicker";
|
+ ".RfcommChannelPicker";
|
||||||
Class<?> channelPickerClass = null;
|
Class<?> channelPickerClass = null;
|
||||||
Class<?>[] children = BluetoothAdapter.class.getDeclaredClasses();
|
Class<?>[] children = BluetoothAdapter.class.getDeclaredClasses();
|
||||||
for(Class<?> c : children) {
|
for (Class<?> c : children) {
|
||||||
if(c.getCanonicalName().equals(className)) {
|
if (c.getCanonicalName().equals(className)) {
|
||||||
channelPickerClass = c;
|
channelPickerClass = c;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(channelPickerClass == null)
|
if (channelPickerClass == null)
|
||||||
throw new IOException("Can't find channel picker class");
|
throw new IOException("Can't find channel picker class");
|
||||||
Constructor<?> constructor =
|
Constructor<?> constructor =
|
||||||
channelPickerClass.getDeclaredConstructor(UUID.class);
|
channelPickerClass.getDeclaredConstructor(UUID.class);
|
||||||
@@ -58,7 +58,7 @@ class InsecureBluetooth {
|
|||||||
channelPickerClass.getDeclaredMethod("nextChannel");
|
channelPickerClass.getDeclaredMethod("nextChannel");
|
||||||
nextChannel.setAccessible(true);
|
nextChannel.setAccessible(true);
|
||||||
int channel = (Integer) nextChannel.invoke(channelPicker);
|
int channel = (Integer) nextChannel.invoke(channelPicker);
|
||||||
if(channel == -1) throw new IOException("No available channels");
|
if (channel == -1) throw new IOException("No available channels");
|
||||||
// Listen on the channel
|
// Listen on the channel
|
||||||
BluetoothServerSocket socket = listen(channel);
|
BluetoothServerSocket socket = listen(channel);
|
||||||
// Add a service record
|
// Add a service record
|
||||||
@@ -72,7 +72,7 @@ class InsecureBluetooth {
|
|||||||
addRfcommServiceRecord.setAccessible(true);
|
addRfcommServiceRecord.setAccessible(true);
|
||||||
int handle = (Integer) addRfcommServiceRecord.invoke(mService, name,
|
int handle = (Integer) addRfcommServiceRecord.invoke(mService, name,
|
||||||
new ParcelUuid(uuid), channel, new Binder());
|
new ParcelUuid(uuid), channel, new Binder());
|
||||||
if(handle == -1) {
|
if (handle == -1) {
|
||||||
socket.close();
|
socket.close();
|
||||||
throw new IOException("Can't register SDP record for " + name);
|
throw new IOException("Can't register SDP record for " + name);
|
||||||
}
|
}
|
||||||
@@ -84,16 +84,16 @@ class InsecureBluetooth {
|
|||||||
setCloseHandler.setAccessible(true);
|
setCloseHandler.setAccessible(true);
|
||||||
setCloseHandler.invoke(socket, mHandler, handle);
|
setCloseHandler.invoke(socket, mHandler, handle);
|
||||||
return socket;
|
return socket;
|
||||||
} catch(NoSuchMethodException e) {
|
} catch (NoSuchMethodException e) {
|
||||||
throw new IOException(e.toString());
|
throw new IOException(e.toString());
|
||||||
} catch(NoSuchFieldException e) {
|
} catch (NoSuchFieldException e) {
|
||||||
throw new IOException(e.toString());
|
throw new IOException(e.toString());
|
||||||
} catch(IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
throw new IOException(e.toString());
|
throw new IOException(e.toString());
|
||||||
} catch(InstantiationException e) {
|
} catch (InstantiationException e) {
|
||||||
throw new IOException(e.toString());
|
throw new IOException(e.toString());
|
||||||
} catch(InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
if(e.getCause() instanceof IOException) {
|
if (e.getCause() instanceof IOException) {
|
||||||
throw (IOException) e.getCause();
|
throw (IOException) e.getCause();
|
||||||
} else {
|
} else {
|
||||||
throw new IOException(e.toString());
|
throw new IOException(e.toString());
|
||||||
@@ -116,21 +116,21 @@ class InsecureBluetooth {
|
|||||||
mSocket.getClass().getDeclaredMethod("bindListen");
|
mSocket.getClass().getDeclaredMethod("bindListen");
|
||||||
bindListen.setAccessible(true);
|
bindListen.setAccessible(true);
|
||||||
int errno = (Integer) bindListen.invoke(mSocket);
|
int errno = (Integer) bindListen.invoke(mSocket);
|
||||||
if(errno != 0) {
|
if (errno != 0) {
|
||||||
socket.close();
|
socket.close();
|
||||||
throw new IOException("Can't bind: errno " + errno);
|
throw new IOException("Can't bind: errno " + errno);
|
||||||
}
|
}
|
||||||
return socket;
|
return socket;
|
||||||
} catch(NoSuchMethodException e) {
|
} catch (NoSuchMethodException e) {
|
||||||
throw new IOException(e.toString());
|
throw new IOException(e.toString());
|
||||||
} catch(NoSuchFieldException e) {
|
} catch (NoSuchFieldException e) {
|
||||||
throw new IOException(e.toString());
|
throw new IOException(e.toString());
|
||||||
} catch(IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
throw new IOException(e.toString());
|
throw new IOException(e.toString());
|
||||||
} catch(InstantiationException e) {
|
} catch (InstantiationException e) {
|
||||||
throw new IOException(e.toString());
|
throw new IOException(e.toString());
|
||||||
} catch(InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
if(e.getCause() instanceof IOException) {
|
if (e.getCause() instanceof IOException) {
|
||||||
throw (IOException) e.getCause();
|
throw (IOException) e.getCause();
|
||||||
} else {
|
} else {
|
||||||
throw new IOException(e.toString());
|
throw new IOException(e.toString());
|
||||||
@@ -141,7 +141,7 @@ class InsecureBluetooth {
|
|||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
static BluetoothSocket createSocket(BluetoothDevice device, UUID uuid)
|
static BluetoothSocket createSocket(BluetoothDevice device, UUID uuid)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if(Build.VERSION.SDK_INT >= 10) {
|
if (Build.VERSION.SDK_INT >= 10) {
|
||||||
LOG.info("Creating socket with new API");
|
LOG.info("Creating socket with new API");
|
||||||
return device.createInsecureRfcommSocketToServiceRecord(uuid);
|
return device.createInsecureRfcommSocketToServiceRecord(uuid);
|
||||||
}
|
}
|
||||||
@@ -154,14 +154,14 @@ class InsecureBluetooth {
|
|||||||
constructor.setAccessible(true);
|
constructor.setAccessible(true);
|
||||||
return constructor.newInstance(TYPE_RFCOMM, -1, false, true, device,
|
return constructor.newInstance(TYPE_RFCOMM, -1, false, true, device,
|
||||||
-1, new ParcelUuid(uuid));
|
-1, new ParcelUuid(uuid));
|
||||||
} catch(NoSuchMethodException e) {
|
} catch (NoSuchMethodException e) {
|
||||||
throw new IOException(e.toString());
|
throw new IOException(e.toString());
|
||||||
} catch(IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
throw new IOException(e.toString());
|
throw new IOException(e.toString());
|
||||||
} catch(InstantiationException e) {
|
} catch (InstantiationException e) {
|
||||||
throw new IOException(e.toString());
|
throw new IOException(e.toString());
|
||||||
} catch(InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
if(e.getCause() instanceof IOException) {
|
if (e.getCause() instanceof IOException) {
|
||||||
throw (IOException) e.getCause();
|
throw (IOException) e.getCause();
|
||||||
} else {
|
} else {
|
||||||
throw new IOException(e.toString());
|
throw new IOException(e.toString());
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
|
|||||||
@Override
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
running = false;
|
running = false;
|
||||||
if(networkStateReceiver != null)
|
if (networkStateReceiver != null)
|
||||||
appContext.unregisterReceiver(networkStateReceiver);
|
appContext.unregisterReceiver(networkStateReceiver);
|
||||||
tryToClose(socket);
|
tryToClose(socket);
|
||||||
}
|
}
|
||||||
@@ -54,13 +54,13 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context ctx, Intent i) {
|
public void onReceive(Context ctx, Intent i) {
|
||||||
if(!running) return;
|
if (!running) return;
|
||||||
Object o = ctx.getSystemService(CONNECTIVITY_SERVICE);
|
Object o = ctx.getSystemService(CONNECTIVITY_SERVICE);
|
||||||
ConnectivityManager cm = (ConnectivityManager) o;
|
ConnectivityManager cm = (ConnectivityManager) o;
|
||||||
NetworkInfo net = cm.getActiveNetworkInfo();
|
NetworkInfo net = cm.getActiveNetworkInfo();
|
||||||
if(net != null && net.getType() == TYPE_WIFI && net.isConnected()) {
|
if (net != null && net.getType() == TYPE_WIFI && net.isConnected()) {
|
||||||
LOG.info("Connected to Wi-Fi");
|
LOG.info("Connected to Wi-Fi");
|
||||||
if(socket == null || socket.isClosed()) bind();
|
if (socket == null || socket.isClosed()) bind();
|
||||||
} else {
|
} else {
|
||||||
LOG.info("Not connected to Wi-Fi");
|
LOG.info("Not connected to Wi-Fi");
|
||||||
tryToClose(socket);
|
tryToClose(socket);
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ class TorPlugin implements DuplexPlugin, EventHandler {
|
|||||||
this.maxLatency = maxLatency;
|
this.maxLatency = maxLatency;
|
||||||
this.maxIdleTime = maxIdleTime;
|
this.maxIdleTime = maxIdleTime;
|
||||||
this.pollingInterval = pollingInterval;
|
this.pollingInterval = pollingInterval;
|
||||||
if(maxIdleTime > Integer.MAX_VALUE / 2)
|
if (maxIdleTime > Integer.MAX_VALUE / 2)
|
||||||
socketTimeout = Integer.MAX_VALUE;
|
socketTimeout = Integer.MAX_VALUE;
|
||||||
else socketTimeout = maxIdleTime * 2;
|
else socketTimeout = maxIdleTime * 2;
|
||||||
torDirectory = appContext.getDir("tor", MODE_PRIVATE);
|
torDirectory = appContext.getDir("tor", MODE_PRIVATE);
|
||||||
@@ -131,16 +131,16 @@ class TorPlugin implements DuplexPlugin, EventHandler {
|
|||||||
try {
|
try {
|
||||||
controlSocket = new Socket("127.0.0.1", CONTROL_PORT);
|
controlSocket = new Socket("127.0.0.1", CONTROL_PORT);
|
||||||
LOG.info("Tor is already running");
|
LOG.info("Tor is already running");
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
LOG.info("Tor is not running");
|
LOG.info("Tor is not running");
|
||||||
startProcess = true;
|
startProcess = true;
|
||||||
// Install the binary, possibly overwriting an older version
|
// Install the binary, possibly overwriting an older version
|
||||||
if(!installBinary()) {
|
if (!installBinary()) {
|
||||||
LOG.warning("Could not install Tor binary");
|
LOG.warning("Could not install Tor binary");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Install the GeoIP database and config file if necessary
|
// Install the GeoIP database and config file if necessary
|
||||||
if(!isConfigInstalled() && !installConfig()) {
|
if (!isConfigInstalled() && !installConfig()) {
|
||||||
LOG.info("Could not install Tor config");
|
LOG.info("Could not install Tor config");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -160,31 +160,31 @@ class TorPlugin implements DuplexPlugin, EventHandler {
|
|||||||
Process torProcess;
|
Process torProcess;
|
||||||
try {
|
try {
|
||||||
torProcess = Runtime.getRuntime().exec(cmd, env, torDirectory);
|
torProcess = Runtime.getRuntime().exec(cmd, env, torDirectory);
|
||||||
} catch(SecurityException e1) {
|
} catch (SecurityException e1) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e1.toString(), e1);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e1.toString(), e1);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Log the process's standard output until it detaches
|
// Log the process's standard output until it detaches
|
||||||
if(LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
Scanner stdout = new Scanner(torProcess.getInputStream());
|
Scanner stdout = new Scanner(torProcess.getInputStream());
|
||||||
while(stdout.hasNextLine()) LOG.info(stdout.nextLine());
|
while (stdout.hasNextLine()) LOG.info(stdout.nextLine());
|
||||||
stdout.close();
|
stdout.close();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// Wait for the process to detach or exit
|
// Wait for the process to detach or exit
|
||||||
int exit = torProcess.waitFor();
|
int exit = torProcess.waitFor();
|
||||||
if(exit != 0) {
|
if (exit != 0) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.warning("Tor exited with value " + exit);
|
LOG.warning("Tor exited with value " + exit);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Wait for the auth cookie file to be created/updated
|
// Wait for the auth cookie file to be created/updated
|
||||||
if(!latch.await(COOKIE_TIMEOUT, MILLISECONDS)) {
|
if (!latch.await(COOKIE_TIMEOUT, MILLISECONDS)) {
|
||||||
LOG.warning("Auth cookie not created");
|
LOG.warning("Auth cookie not created");
|
||||||
if(LOG.isLoggable(INFO)) listFiles(torDirectory);
|
if (LOG.isLoggable(INFO)) listFiles(torDirectory);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch(InterruptedException e1) {
|
} catch (InterruptedException e1) {
|
||||||
LOG.warning("Interrupted while starting Tor");
|
LOG.warning("Interrupted while starting Tor");
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
return false;
|
return false;
|
||||||
@@ -203,9 +203,9 @@ class TorPlugin implements DuplexPlugin, EventHandler {
|
|||||||
controlConnection.setEventHandler(this);
|
controlConnection.setEventHandler(this);
|
||||||
controlConnection.setEvents(Arrays.asList(EVENTS));
|
controlConnection.setEvents(Arrays.asList(EVENTS));
|
||||||
// If Tor was already running, find out whether it's bootstrapped
|
// If Tor was already running, find out whether it's bootstrapped
|
||||||
if(!startProcess) {
|
if (!startProcess) {
|
||||||
String phase = controlConnection.getInfo("status/bootstrap-phase");
|
String phase = controlConnection.getInfo("status/bootstrap-phase");
|
||||||
if(phase != null && phase.contains("PROGRESS=100")) {
|
if (phase != null && phase.contains("PROGRESS=100")) {
|
||||||
LOG.info("Tor has already bootstrapped");
|
LOG.info("Tor has already bootstrapped");
|
||||||
bootstrapped = true;
|
bootstrapped = true;
|
||||||
}
|
}
|
||||||
@@ -228,13 +228,13 @@ class TorPlugin implements DuplexPlugin, EventHandler {
|
|||||||
out = new FileOutputStream(torFile);
|
out = new FileOutputStream(torFile);
|
||||||
copy(in, out);
|
copy(in, out);
|
||||||
// Make the Tor binary executable
|
// Make the Tor binary executable
|
||||||
if(!setExecutable(torFile)) {
|
if (!setExecutable(torFile)) {
|
||||||
LOG.warning("Could not make Tor binary executable");
|
LOG.warning("Could not make Tor binary executable");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
tryToClose(in);
|
tryToClose(in);
|
||||||
tryToClose(out);
|
tryToClose(out);
|
||||||
return false;
|
return false;
|
||||||
@@ -260,8 +260,8 @@ class TorPlugin implements DuplexPlugin, EventHandler {
|
|||||||
// Create a file to indicate that installation succeeded
|
// Create a file to indicate that installation succeeded
|
||||||
doneFile.createNewFile();
|
doneFile.createNewFile();
|
||||||
return true;
|
return true;
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
tryToClose(in);
|
tryToClose(in);
|
||||||
tryToClose(out);
|
tryToClose(out);
|
||||||
return false;
|
return false;
|
||||||
@@ -269,12 +269,12 @@ class TorPlugin implements DuplexPlugin, EventHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private InputStream getTorInputStream() throws IOException {
|
private InputStream getTorInputStream() throws IOException {
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Installing Tor binary for " + architecture);
|
LOG.info("Installing Tor binary for " + architecture);
|
||||||
String filename = "tor-" + architecture + ".zip";
|
String filename = "tor-" + architecture + ".zip";
|
||||||
InputStream in = appContext.getResources().getAssets().open(filename);
|
InputStream in = appContext.getResources().getAssets().open(filename);
|
||||||
ZipInputStream zin = new ZipInputStream(in);
|
ZipInputStream zin = new ZipInputStream(in);
|
||||||
if(zin.getNextEntry() == null) throw new IOException();
|
if (zin.getNextEntry() == null) throw new IOException();
|
||||||
return zin;
|
return zin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,7 +282,7 @@ class TorPlugin implements DuplexPlugin, EventHandler {
|
|||||||
String filename = "geoip.zip";
|
String filename = "geoip.zip";
|
||||||
InputStream in = appContext.getResources().getAssets().open(filename);
|
InputStream in = appContext.getResources().getAssets().open(filename);
|
||||||
ZipInputStream zin = new ZipInputStream(in);
|
ZipInputStream zin = new ZipInputStream(in);
|
||||||
if(zin.getNextEntry() == null) throw new IOException();
|
if (zin.getNextEntry() == null) throw new IOException();
|
||||||
return zin;
|
return zin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,9 +292,9 @@ class TorPlugin implements DuplexPlugin, EventHandler {
|
|||||||
|
|
||||||
private void copy(InputStream in, OutputStream out) throws IOException {
|
private void copy(InputStream in, OutputStream out) throws IOException {
|
||||||
byte[] buf = new byte[4096];
|
byte[] buf = new byte[4096];
|
||||||
while(true) {
|
while (true) {
|
||||||
int read = in.read(buf);
|
int read = in.read(buf);
|
||||||
if(read == -1) break;
|
if (read == -1) break;
|
||||||
out.write(buf, 0, read);
|
out.write(buf, 0, read);
|
||||||
}
|
}
|
||||||
in.close();
|
in.close();
|
||||||
@@ -303,19 +303,19 @@ class TorPlugin implements DuplexPlugin, EventHandler {
|
|||||||
|
|
||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
private boolean setExecutable(File f) {
|
private boolean setExecutable(File f) {
|
||||||
if(Build.VERSION.SDK_INT >= 9) {
|
if (Build.VERSION.SDK_INT >= 9) {
|
||||||
return f.setExecutable(true, true);
|
return f.setExecutable(true, true);
|
||||||
} else {
|
} else {
|
||||||
String[] command = { "chmod", "700", f.getAbsolutePath() };
|
String[] command = { "chmod", "700", f.getAbsolutePath() };
|
||||||
try {
|
try {
|
||||||
return Runtime.getRuntime().exec(command).waitFor() == 0;
|
return Runtime.getRuntime().exec(command).waitFor() == 0;
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
} catch(InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.warning("Interrupted while executing chmod");
|
LOG.warning("Interrupted while executing chmod");
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
} catch(SecurityException e) {
|
} catch (SecurityException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -323,22 +323,22 @@ class TorPlugin implements DuplexPlugin, EventHandler {
|
|||||||
|
|
||||||
private void tryToClose(InputStream in) {
|
private void tryToClose(InputStream in) {
|
||||||
try {
|
try {
|
||||||
if(in != null) in.close();
|
if (in != null) in.close();
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tryToClose(OutputStream out) {
|
private void tryToClose(OutputStream out) {
|
||||||
try {
|
try {
|
||||||
if(out != null) out.close();
|
if (out != null) out.close();
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void listFiles(File f) {
|
private void listFiles(File f) {
|
||||||
if(f.isDirectory()) for(File child : f.listFiles()) listFiles(child);
|
if (f.isDirectory()) for (File child : f.listFiles()) listFiles(child);
|
||||||
else LOG.info(f.getAbsolutePath());
|
else LOG.info(f.getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,9 +347,9 @@ class TorPlugin implements DuplexPlugin, EventHandler {
|
|||||||
FileInputStream in = new FileInputStream(f);
|
FileInputStream in = new FileInputStream(f);
|
||||||
try {
|
try {
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
while(offset < b.length) {
|
while (offset < b.length) {
|
||||||
int read = in.read(b, offset, b.length - offset);
|
int read = in.read(b, offset, b.length - offset);
|
||||||
if(read == -1) throw new EOFException();
|
if (read == -1) throw new EOFException();
|
||||||
offset += read;
|
offset += read;
|
||||||
}
|
}
|
||||||
return b;
|
return b;
|
||||||
@@ -364,19 +364,19 @@ class TorPlugin implements DuplexPlugin, EventHandler {
|
|||||||
// If there's already a port number stored in config, reuse it
|
// If there's already a port number stored in config, reuse it
|
||||||
String portString = callback.getConfig().get("port");
|
String portString = callback.getConfig().get("port");
|
||||||
int port;
|
int port;
|
||||||
if(StringUtils.isNullOrEmpty(portString)) port = 0;
|
if (StringUtils.isNullOrEmpty(portString)) port = 0;
|
||||||
else port = Integer.parseInt(portString);
|
else port = Integer.parseInt(portString);
|
||||||
// Bind a server socket to receive connections from Tor
|
// Bind a server socket to receive connections from Tor
|
||||||
ServerSocket ss = null;
|
ServerSocket ss = null;
|
||||||
try {
|
try {
|
||||||
ss = new ServerSocket();
|
ss = new ServerSocket();
|
||||||
ss.bind(new InetSocketAddress("127.0.0.1", port));
|
ss.bind(new InetSocketAddress("127.0.0.1", port));
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
tryToClose(ss);
|
tryToClose(ss);
|
||||||
}
|
}
|
||||||
if(!running) {
|
if (!running) {
|
||||||
tryToClose(ss);
|
tryToClose(ss);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -400,15 +400,15 @@ class TorPlugin implements DuplexPlugin, EventHandler {
|
|||||||
|
|
||||||
private void tryToClose(ServerSocket ss) {
|
private void tryToClose(ServerSocket ss) {
|
||||||
try {
|
try {
|
||||||
if(ss != null) ss.close();
|
if (ss != null) ss.close();
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void publishHiddenService(String port) {
|
private void publishHiddenService(String port) {
|
||||||
if(!running) return;
|
if (!running) return;
|
||||||
if(!hostnameFile.exists()) {
|
if (!hostnameFile.exists()) {
|
||||||
LOG.info("Creating hidden service");
|
LOG.info("Creating hidden service");
|
||||||
try {
|
try {
|
||||||
// Watch for the hostname file being created/updated
|
// Watch for the hostname file being created/updated
|
||||||
@@ -424,15 +424,15 @@ class TorPlugin implements DuplexPlugin, EventHandler {
|
|||||||
controlConnection.setConf(config);
|
controlConnection.setConf(config);
|
||||||
controlConnection.saveConf();
|
controlConnection.saveConf();
|
||||||
// Wait for the hostname file to be created/updated
|
// Wait for the hostname file to be created/updated
|
||||||
if(!latch.await(HOSTNAME_TIMEOUT, MILLISECONDS)) {
|
if (!latch.await(HOSTNAME_TIMEOUT, MILLISECONDS)) {
|
||||||
LOG.warning("Hidden service not created");
|
LOG.warning("Hidden service not created");
|
||||||
if(LOG.isLoggable(INFO)) listFiles(torDirectory);
|
if (LOG.isLoggable(INFO)) listFiles(torDirectory);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(!running) return;
|
if (!running) return;
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
} catch(InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.warning("Interrupted while creating hidden service");
|
LOG.warning("Interrupted while creating hidden service");
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
return;
|
return;
|
||||||
@@ -441,24 +441,24 @@ class TorPlugin implements DuplexPlugin, EventHandler {
|
|||||||
// Publish the hidden service's onion hostname in transport properties
|
// Publish the hidden service's onion hostname in transport properties
|
||||||
try {
|
try {
|
||||||
String hostname = new String(read(hostnameFile), "UTF-8").trim();
|
String hostname = new String(read(hostnameFile), "UTF-8").trim();
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("Hidden service " + hostname);
|
if (LOG.isLoggable(INFO)) LOG.info("Hidden service " + hostname);
|
||||||
TransportProperties p = new TransportProperties();
|
TransportProperties p = new TransportProperties();
|
||||||
p.put("onion", hostname);
|
p.put("onion", hostname);
|
||||||
callback.mergeLocalProperties(p);
|
callback.mergeLocalProperties(p);
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void acceptContactConnections(ServerSocket ss) {
|
private void acceptContactConnections(ServerSocket ss) {
|
||||||
while(running) {
|
while (running) {
|
||||||
Socket s;
|
Socket s;
|
||||||
try {
|
try {
|
||||||
s = ss.accept();
|
s = ss.accept();
|
||||||
s.setSoTimeout(socketTimeout);
|
s.setSoTimeout(socketTimeout);
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
// This is expected when the socket is closed
|
// This is expected when the socket is closed
|
||||||
if(LOG.isLoggable(INFO)) LOG.info(e.toString());
|
if (LOG.isLoggable(INFO)) LOG.info(e.toString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LOG.info("Connection received");
|
LOG.info("Connection received");
|
||||||
@@ -468,9 +468,9 @@ class TorPlugin implements DuplexPlugin, EventHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void enableNetwork(boolean enable) throws IOException {
|
private void enableNetwork(boolean enable) throws IOException {
|
||||||
if(!running) return;
|
if (!running) return;
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("Enabling network: " + enable);
|
if (LOG.isLoggable(INFO)) LOG.info("Enabling network: " + enable);
|
||||||
if(!enable) circuitBuilt.set(false);
|
if (!enable) circuitBuilt.set(false);
|
||||||
networkEnabled = enable;
|
networkEnabled = enable;
|
||||||
controlConnection.setConf("DisableNetwork", enable ? "0" : "1");
|
controlConnection.setConf("DisableNetwork", enable ? "0" : "1");
|
||||||
}
|
}
|
||||||
@@ -478,21 +478,21 @@ class TorPlugin implements DuplexPlugin, EventHandler {
|
|||||||
public void stop() throws IOException {
|
public void stop() throws IOException {
|
||||||
running = false;
|
running = false;
|
||||||
tryToClose(socket);
|
tryToClose(socket);
|
||||||
if(networkStateReceiver != null)
|
if (networkStateReceiver != null)
|
||||||
appContext.unregisterReceiver(networkStateReceiver);
|
appContext.unregisterReceiver(networkStateReceiver);
|
||||||
try {
|
try {
|
||||||
LOG.info("Stopping Tor");
|
LOG.info("Stopping Tor");
|
||||||
if(controlSocket == null)
|
if (controlSocket == null)
|
||||||
controlSocket = new Socket("127.0.0.1", CONTROL_PORT);
|
controlSocket = new Socket("127.0.0.1", CONTROL_PORT);
|
||||||
if(controlConnection == null) {
|
if (controlConnection == null) {
|
||||||
controlConnection = new TorControlConnection(controlSocket);
|
controlConnection = new TorControlConnection(controlSocket);
|
||||||
controlConnection.authenticate(read(cookieFile));
|
controlConnection.authenticate(read(cookieFile));
|
||||||
}
|
}
|
||||||
controlConnection.setConf("DisableNetwork", "1");
|
controlConnection.setConf("DisableNetwork", "1");
|
||||||
controlConnection.shutdownTor("TERM");
|
controlConnection.shutdownTor("TERM");
|
||||||
controlSocket.close();
|
controlSocket.close();
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -509,41 +509,41 @@ class TorPlugin implements DuplexPlugin, EventHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void poll(Collection<ContactId> connected) {
|
public void poll(Collection<ContactId> connected) {
|
||||||
if(!isRunning()) return;
|
if (!isRunning()) return;
|
||||||
for(ContactId c : callback.getRemoteProperties().keySet())
|
for (ContactId c : callback.getRemoteProperties().keySet())
|
||||||
if(!connected.contains(c)) connectAndCallBack(c);
|
if (!connected.contains(c)) connectAndCallBack(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connectAndCallBack(final ContactId c) {
|
private void connectAndCallBack(final ContactId c) {
|
||||||
ioExecutor.execute(new Runnable() {
|
ioExecutor.execute(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
DuplexTransportConnection d = createConnection(c);
|
DuplexTransportConnection d = createConnection(c);
|
||||||
if(d != null) callback.outgoingConnectionCreated(c, d);
|
if (d != null) callback.outgoingConnectionCreated(c, d);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public DuplexTransportConnection createConnection(ContactId c) {
|
public DuplexTransportConnection createConnection(ContactId c) {
|
||||||
if(!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
TransportProperties p = callback.getRemoteProperties().get(c);
|
TransportProperties p = callback.getRemoteProperties().get(c);
|
||||||
if(p == null) return null;
|
if (p == null) return null;
|
||||||
String onion = p.get("onion");
|
String onion = p.get("onion");
|
||||||
if(StringUtils.isNullOrEmpty(onion)) return null;
|
if (StringUtils.isNullOrEmpty(onion)) return null;
|
||||||
if(!ONION.matcher(onion).matches()) {
|
if (!ONION.matcher(onion).matches()) {
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("Invalid hostname: " + onion);
|
if (LOG.isLoggable(INFO)) LOG.info("Invalid hostname: " + onion);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("Connecting to " + onion);
|
if (LOG.isLoggable(INFO)) LOG.info("Connecting to " + onion);
|
||||||
controlConnection.forgetHiddenService(onion.substring(0, 16));
|
controlConnection.forgetHiddenService(onion.substring(0, 16));
|
||||||
Socks5Proxy proxy = new Socks5Proxy("127.0.0.1", SOCKS_PORT);
|
Socks5Proxy proxy = new Socks5Proxy("127.0.0.1", SOCKS_PORT);
|
||||||
proxy.resolveAddrLocally(false);
|
proxy.resolveAddrLocally(false);
|
||||||
Socket s = new SocksSocket(proxy, onion, 80);
|
Socket s = new SocksSocket(proxy, onion, 80);
|
||||||
s.setSoTimeout(socketTimeout);
|
s.setSoTimeout(socketTimeout);
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("Connected to " + onion);
|
if (LOG.isLoggable(INFO)) LOG.info("Connected to " + onion);
|
||||||
return new TorTransportConnection(this, s);
|
return new TorTransportConnection(this, s);
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("Could not connect to " + onion);
|
if (LOG.isLoggable(INFO)) LOG.info("Could not connect to " + onion);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -558,16 +558,16 @@ class TorPlugin implements DuplexPlugin, EventHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void circuitStatus(String status, String id, String path) {
|
public void circuitStatus(String status, String id, String path) {
|
||||||
if(status.equals("BUILT") && !circuitBuilt.getAndSet(true)) {
|
if (status.equals("BUILT") && !circuitBuilt.getAndSet(true)) {
|
||||||
LOG.info("First circuit built");
|
LOG.info("First circuit built");
|
||||||
if(isRunning()) callback.pollNow();
|
if (isRunning()) callback.pollNow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void streamStatus(String status, String id, String target) {}
|
public void streamStatus(String status, String id, String target) {}
|
||||||
|
|
||||||
public void orConnStatus(String status, String orName) {
|
public void orConnStatus(String status, String orName) {
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("OR connection " + status);
|
if (LOG.isLoggable(INFO)) LOG.info("OR connection " + status);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bandwidthUsed(long read, long written) {}
|
public void bandwidthUsed(long read, long written) {}
|
||||||
@@ -575,10 +575,10 @@ class TorPlugin implements DuplexPlugin, EventHandler {
|
|||||||
public void newDescriptors(List<String> orList) {}
|
public void newDescriptors(List<String> orList) {}
|
||||||
|
|
||||||
public void message(String severity, String msg) {
|
public void message(String severity, String msg) {
|
||||||
if(LOG.isLoggable(INFO)) LOG.info(severity + " " + msg);
|
if (LOG.isLoggable(INFO)) LOG.info(severity + " " + msg);
|
||||||
if(severity.equals("NOTICE") && msg.startsWith("Bootstrapped 100%")) {
|
if (severity.equals("NOTICE") && msg.startsWith("Bootstrapped 100%")) {
|
||||||
bootstrapped = true;
|
bootstrapped = true;
|
||||||
if(isRunning()) callback.pollNow();
|
if (isRunning()) callback.pollNow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -604,26 +604,26 @@ class TorPlugin implements DuplexPlugin, EventHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context ctx, Intent i) {
|
public void onReceive(Context ctx, Intent i) {
|
||||||
if(!running) return;
|
if (!running) return;
|
||||||
boolean online = !i.getBooleanExtra(EXTRA_NO_CONNECTIVITY, false);
|
boolean online = !i.getBooleanExtra(EXTRA_NO_CONNECTIVITY, false);
|
||||||
if(online) {
|
if (online) {
|
||||||
// Some devices fail to set EXTRA_NO_CONNECTIVITY, double check
|
// Some devices fail to set EXTRA_NO_CONNECTIVITY, double check
|
||||||
Object o = ctx.getSystemService(CONNECTIVITY_SERVICE);
|
Object o = ctx.getSystemService(CONNECTIVITY_SERVICE);
|
||||||
ConnectivityManager cm = (ConnectivityManager) o;
|
ConnectivityManager cm = (ConnectivityManager) o;
|
||||||
NetworkInfo net = cm.getActiveNetworkInfo();
|
NetworkInfo net = cm.getActiveNetworkInfo();
|
||||||
if(net == null || !net.isConnected()) online = false;
|
if (net == null || !net.isConnected()) online = false;
|
||||||
}
|
}
|
||||||
String country = locationUtils.getCurrentCountry();
|
String country = locationUtils.getCurrentCountry();
|
||||||
if(LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
LOG.info("Online: " + online);
|
LOG.info("Online: " + online);
|
||||||
if("".equals(country)) LOG.info("Country code unknown");
|
if ("".equals(country)) LOG.info("Country code unknown");
|
||||||
else LOG.info("Country code: " + country);
|
else LOG.info("Country code: " + country);
|
||||||
}
|
}
|
||||||
boolean blocked = TorNetworkMetadata.isTorProbablyBlocked(country);
|
boolean blocked = TorNetworkMetadata.isTorProbablyBlocked(country);
|
||||||
try {
|
try {
|
||||||
enableNetwork(online && !blocked);
|
enableNetwork(online && !blocked);
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,21 +40,21 @@ public class TorPluginFactory implements DuplexPluginFactory {
|
|||||||
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
|
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
|
||||||
// Check that we have a Tor binary for this architecture
|
// Check that we have a Tor binary for this architecture
|
||||||
String architecture = null;
|
String architecture = null;
|
||||||
for(String abi : AndroidUtils.getSupportedArchitectures()) {
|
for (String abi : AndroidUtils.getSupportedArchitectures()) {
|
||||||
if(abi.startsWith("x86")) {
|
if (abi.startsWith("x86")) {
|
||||||
architecture = "x86";
|
architecture = "x86";
|
||||||
break;
|
break;
|
||||||
} else if(abi.startsWith("armeabi")) {
|
} else if (abi.startsWith("armeabi")) {
|
||||||
architecture = "arm";
|
architecture = "arm";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(architecture == null) {
|
if (architecture == null) {
|
||||||
LOG.info("Tor is not supported on this architecture");
|
LOG.info("Tor is not supported on this architecture");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// Use position-independent executable for SDK >= 16
|
// Use position-independent executable for SDK >= 16
|
||||||
if(Build.VERSION.SDK_INT >= 16) architecture += "-pie";
|
if (Build.VERSION.SDK_INT >= 16) architecture += "-pie";
|
||||||
return new TorPlugin(ioExecutor,appContext, locationUtils, callback,
|
return new TorPlugin(ioExecutor,appContext, locationUtils, callback,
|
||||||
architecture, MAX_LATENCY, MAX_IDLE_TIME, POLLING_INTERVAL);
|
architecture, MAX_LATENCY, MAX_IDLE_TIME, POLLING_INTERVAL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,8 +48,8 @@ class TorTransportConnection implements DuplexTransportConnection {
|
|||||||
|
|
||||||
public void dispose(boolean exception, boolean recognised)
|
public void dispose(boolean exception, boolean recognised)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if(halfClosed.getAndSet(true) || exception)
|
if (halfClosed.getAndSet(true) || exception)
|
||||||
if(!closed.getAndSet(true)) socket.close();
|
if (!closed.getAndSet(true)) socket.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,8 +72,8 @@ class TorTransportConnection implements DuplexTransportConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void dispose(boolean exception) throws IOException {
|
public void dispose(boolean exception) throws IOException {
|
||||||
if(halfClosed.getAndSet(true) || exception)
|
if (halfClosed.getAndSet(true) || exception)
|
||||||
if(!closed.getAndSet(true)) socket.close();
|
if (!closed.getAndSet(true)) socket.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public class AndroidFileUtils implements FileUtils {
|
|||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public long getTotalSpace(File f) throws IOException {
|
public long getTotalSpace(File f) throws IOException {
|
||||||
if(Build.VERSION.SDK_INT >= 9) return f.getTotalSpace();
|
if (Build.VERSION.SDK_INT >= 9) return f.getTotalSpace();
|
||||||
StatFs s = new StatFs(f.getAbsolutePath());
|
StatFs s = new StatFs(f.getAbsolutePath());
|
||||||
// These deprecated methods are the best thing available for SDK < 9
|
// These deprecated methods are the best thing available for SDK < 9
|
||||||
return (long) s.getBlockCount() * s.getBlockSize();
|
return (long) s.getBlockCount() * s.getBlockSize();
|
||||||
@@ -23,7 +23,7 @@ public class AndroidFileUtils implements FileUtils {
|
|||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public long getFreeSpace(File f) throws IOException {
|
public long getFreeSpace(File f) throws IOException {
|
||||||
if(Build.VERSION.SDK_INT >= 9) return f.getUsableSpace();
|
if (Build.VERSION.SDK_INT >= 9) return f.getUsableSpace();
|
||||||
StatFs s = new StatFs(f.getAbsolutePath());
|
StatFs s = new StatFs(f.getAbsolutePath());
|
||||||
// These deprecated methods are the best thing available for SDK < 9
|
// These deprecated methods are the best thing available for SDK < 9
|
||||||
return (long) s.getAvailableBlocks() * s.getBlockSize();
|
return (long) s.getAvailableBlocks() * s.getBlockSize();
|
||||||
|
|||||||
@@ -47,14 +47,14 @@ class AndroidLocationUtils implements LocationUtils {
|
|||||||
@SuppressLint("DefaultLocale")
|
@SuppressLint("DefaultLocale")
|
||||||
public String getCurrentCountry() {
|
public String getCurrentCountry() {
|
||||||
String countryCode = getCountryFromPhoneNetwork();
|
String countryCode = getCountryFromPhoneNetwork();
|
||||||
if(!TextUtils.isEmpty(countryCode)) return countryCode.toUpperCase();
|
if (!TextUtils.isEmpty(countryCode)) return countryCode.toUpperCase();
|
||||||
// Disabled because it involves a network call; requires
|
// Disabled because it involves a network call; requires
|
||||||
// ACCESS_FINE_LOCATION
|
// ACCESS_FINE_LOCATION
|
||||||
// countryCode = getCountryFromLocation();
|
// countryCode = getCountryFromLocation();
|
||||||
// if(!TextUtils.isEmpty(countryCode)) return countryCode;
|
// if (!TextUtils.isEmpty(countryCode)) return countryCode;
|
||||||
LOG.info("Falling back to SIM card country");
|
LOG.info("Falling back to SIM card country");
|
||||||
countryCode = getCountryFromSimCard();
|
countryCode = getCountryFromSimCard();
|
||||||
if(!TextUtils.isEmpty(countryCode)) return countryCode.toUpperCase();
|
if (!TextUtils.isEmpty(countryCode)) return countryCode.toUpperCase();
|
||||||
LOG.info("Falling back to user-defined locale");
|
LOG.info("Falling back to user-defined locale");
|
||||||
return Locale.getDefault().getCountry();
|
return Locale.getDefault().getCountry();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ class AndroidSeedProvider extends LinuxSeedProvider {
|
|||||||
out.writeInt(android.os.Process.myTid());
|
out.writeInt(android.os.Process.myTid());
|
||||||
out.writeInt(android.os.Process.myUid());
|
out.writeInt(android.os.Process.myUid());
|
||||||
String fingerprint = Build.FINGERPRINT;
|
String fingerprint = Build.FINGERPRINT;
|
||||||
if(fingerprint != null) out.writeUTF(fingerprint);
|
if (fingerprint != null) out.writeUTF(fingerprint);
|
||||||
if(Build.VERSION.SDK_INT >= 9) {
|
if (Build.VERSION.SDK_INT >= 9) {
|
||||||
String serial = Build.SERIAL;
|
String serial = Build.SERIAL;
|
||||||
if(serial != null) out.writeUTF(serial);
|
if (serial != null) out.writeUTF(serial);
|
||||||
}
|
}
|
||||||
super.writeToEntropyPool(out);
|
super.writeToEntropyPool(out);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ public class Author {
|
|||||||
int length;
|
int length;
|
||||||
try {
|
try {
|
||||||
length = name.getBytes("UTF-8").length;
|
length = name.getBytes("UTF-8").length;
|
||||||
} catch(UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
if(length == 0 || length > MAX_AUTHOR_NAME_LENGTH)
|
if (length == 0 || length > MAX_AUTHOR_NAME_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public class AuthorId extends UniqueId {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if(o instanceof AuthorId)
|
if (o instanceof AuthorId)
|
||||||
return Arrays.equals(id, ((AuthorId) o).id);
|
return Arrays.equals(id, ((AuthorId) o).id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,13 +21,13 @@ public class Bytes {
|
|||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
// Thread-safe because if two or more threads check and update the
|
// Thread-safe because if two or more threads check and update the
|
||||||
// value, they'll calculate the same value
|
// value, they'll calculate the same value
|
||||||
if(hashCode == -1) hashCode = Arrays.hashCode(bytes);
|
if (hashCode == -1) hashCode = Arrays.hashCode(bytes);
|
||||||
return hashCode;
|
return hashCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if(o instanceof Bytes)
|
if (o instanceof Bytes)
|
||||||
return Arrays.equals(bytes, ((Bytes) o).bytes);
|
return Arrays.equals(bytes, ((Bytes) o).bytes);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public class Contact {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if(o instanceof Contact) return id.equals(((Contact) o).id);
|
if (o instanceof Contact) return id.equals(((Contact) o).id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public class ContactId {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if(o instanceof ContactId) return id == ((ContactId) o).id;
|
if (o instanceof ContactId) return id == ((ContactId) o).id;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ abstract class StringMap extends Hashtable<String, String> {
|
|||||||
|
|
||||||
public boolean getBoolean(String key, boolean defaultValue) {
|
public boolean getBoolean(String key, boolean defaultValue) {
|
||||||
String s = get(key);
|
String s = get(key);
|
||||||
if(s == null) return defaultValue;
|
if (s == null) return defaultValue;
|
||||||
if("true".equals(s)) return true;
|
if ("true".equals(s)) return true;
|
||||||
if("false".equals(s)) return false;
|
if ("false".equals(s)) return false;
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ public class TransportId {
|
|||||||
private final String id;
|
private final String id;
|
||||||
|
|
||||||
public TransportId(String id) {
|
public TransportId(String id) {
|
||||||
if(id.length() == 0 || id.length() > MAX_TRANSPORT_ID_LENGTH)
|
if (id.length() == 0 || id.length() > MAX_TRANSPORT_ID_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
@@ -21,7 +21,7 @@ public class TransportId {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if(o instanceof TransportId) return id.equals(((TransportId) o).id);
|
if (o instanceof TransportId) return id.equals(((TransportId) o).id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ public abstract class UniqueId {
|
|||||||
private int hashCode = -1;
|
private int hashCode = -1;
|
||||||
|
|
||||||
protected UniqueId(byte[] id) {
|
protected UniqueId(byte[] id) {
|
||||||
if(id.length != LENGTH) throw new IllegalArgumentException();
|
if (id.length != LENGTH) throw new IllegalArgumentException();
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ public abstract class UniqueId {
|
|||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
// Thread-safe because if two or more threads check and update the
|
// Thread-safe because if two or more threads check and update the
|
||||||
// value, they'll calculate the same value
|
// value, they'll calculate the same value
|
||||||
if(hashCode == -1) hashCode = Arrays.hashCode(id);
|
if (hashCode == -1) hashCode = Arrays.hashCode(id);
|
||||||
return hashCode;
|
return hashCode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ public class SecretKey {
|
|||||||
private final byte[] key;
|
private final byte[] key;
|
||||||
|
|
||||||
public SecretKey(byte[] key) {
|
public SecretKey(byte[] key) {
|
||||||
if(key.length != LENGTH) throw new IllegalArgumentException();
|
if (key.length != LENGTH) throw new IllegalArgumentException();
|
||||||
this.key = key;
|
this.key = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,12 +16,12 @@ public class Group {
|
|||||||
int length;
|
int length;
|
||||||
try {
|
try {
|
||||||
length = name.getBytes("UTF-8").length;
|
length = name.getBytes("UTF-8").length;
|
||||||
} catch(UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
if(length == 0 || length > MAX_GROUP_NAME_LENGTH)
|
if (length == 0 || length > MAX_GROUP_NAME_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
if(salt.length != GROUP_SALT_LENGTH)
|
if (salt.length != GROUP_SALT_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public class GroupId extends UniqueId {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if(o instanceof GroupId)
|
if (o instanceof GroupId)
|
||||||
return Arrays.equals(id, ((GroupId) o).id);
|
return Arrays.equals(id, ((GroupId) o).id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ public class MessageId extends UniqueId {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if(o instanceof MessageId)
|
if (o instanceof MessageId)
|
||||||
return Arrays.equals(id, ((MessageId) o).id);
|
return Arrays.equals(id, ((MessageId) o).id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ public class TemporarySecret extends Endpoint {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if(o instanceof TemporarySecret) {
|
if (o instanceof TemporarySecret) {
|
||||||
TemporarySecret s = (TemporarySecret) o;
|
TemporarySecret s = (TemporarySecret) o;
|
||||||
return contactId.equals(s.contactId) &&
|
return contactId.equals(s.contactId) &&
|
||||||
transportId.equals(s.transportId) && period == s.period;
|
transportId.equals(s.transportId) && period == s.period;
|
||||||
|
|||||||
@@ -26,15 +26,15 @@ class AuthenticatedCipherImpl implements AuthenticatedCipher {
|
|||||||
public int process(byte[] input, int inputOff, int len, byte[] output,
|
public int process(byte[] input, int inputOff, int len, byte[] output,
|
||||||
int outputOff) throws GeneralSecurityException {
|
int outputOff) throws GeneralSecurityException {
|
||||||
int processed = 0;
|
int processed = 0;
|
||||||
if(len != 0) {
|
if (len != 0) {
|
||||||
processed = cipher.processBytes(input, inputOff, len, output,
|
processed = cipher.processBytes(input, inputOff, len, output,
|
||||||
outputOff);
|
outputOff);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return processed + cipher.doFinal(output, outputOff + processed);
|
return processed + cipher.doFinal(output, outputOff + processed);
|
||||||
} catch(DataLengthException e) {
|
} catch (DataLengthException e) {
|
||||||
throw new GeneralSecurityException(e.getMessage());
|
throw new GeneralSecurityException(e.getMessage());
|
||||||
} catch(InvalidCipherTextException e) {
|
} catch (InvalidCipherTextException e) {
|
||||||
throw new GeneralSecurityException(e.getMessage());
|
throw new GeneralSecurityException(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,7 +46,7 @@ class AuthenticatedCipherImpl implements AuthenticatedCipher {
|
|||||||
AEADParameters params = new AEADParameters(k, MAC_LENGTH * 8, iv, iv);
|
AEADParameters params = new AEADParameters(k, MAC_LENGTH * 8, iv, iv);
|
||||||
try {
|
try {
|
||||||
cipher.init(encrypt, params);
|
cipher.init(encrypt, params);
|
||||||
} catch(IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
throw new GeneralSecurityException(e.getMessage());
|
throw new GeneralSecurityException(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,17 +24,17 @@ class CombinedSecureRandom extends SecureRandom {
|
|||||||
private final SecureRandom[] randoms;
|
private final SecureRandom[] randoms;
|
||||||
|
|
||||||
private CombinedSecureRandomSpi(SecureRandom... randoms) {
|
private CombinedSecureRandomSpi(SecureRandom... randoms) {
|
||||||
if(randoms.length < 2) throw new IllegalArgumentException();
|
if (randoms.length < 2) throw new IllegalArgumentException();
|
||||||
this.randoms = randoms;
|
this.randoms = randoms;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] engineGenerateSeed(int numBytes) {
|
protected byte[] engineGenerateSeed(int numBytes) {
|
||||||
byte[] combined = new byte[numBytes];
|
byte[] combined = new byte[numBytes];
|
||||||
for(SecureRandom random : randoms) {
|
for (SecureRandom random : randoms) {
|
||||||
byte[] b = random.generateSeed(numBytes);
|
byte[] b = random.generateSeed(numBytes);
|
||||||
int length = Math.min(numBytes, b.length);
|
int length = Math.min(numBytes, b.length);
|
||||||
for(int i = 0; i < length; i++)
|
for (int i = 0; i < length; i++)
|
||||||
combined[i] = (byte) (combined[i] ^ b[i]);
|
combined[i] = (byte) (combined[i] ^ b[i]);
|
||||||
}
|
}
|
||||||
return combined;
|
return combined;
|
||||||
@@ -43,16 +43,16 @@ class CombinedSecureRandom extends SecureRandom {
|
|||||||
@Override
|
@Override
|
||||||
protected void engineNextBytes(byte[] b) {
|
protected void engineNextBytes(byte[] b) {
|
||||||
byte[] temp = new byte[b.length];
|
byte[] temp = new byte[b.length];
|
||||||
for(SecureRandom random : randoms) {
|
for (SecureRandom random : randoms) {
|
||||||
random.nextBytes(temp);
|
random.nextBytes(temp);
|
||||||
for(int i = 0; i < b.length; i++)
|
for (int i = 0; i < b.length; i++)
|
||||||
b[i] = (byte) (b[i] ^ temp[i]);
|
b[i] = (byte) (b[i] ^ temp[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void engineSetSeed(byte[] seed) {
|
protected void engineSetSeed(byte[] seed) {
|
||||||
for(SecureRandom random : randoms) random.setSeed(seed);
|
for (SecureRandom random : randoms) random.setSeed(seed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -79,9 +79,9 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
CryptoComponentImpl(SeedProvider r) {
|
CryptoComponentImpl(SeedProvider r) {
|
||||||
if(!FortunaSecureRandom.selfTest()) throw new RuntimeException();
|
if (!FortunaSecureRandom.selfTest()) throw new RuntimeException();
|
||||||
SecureRandom secureRandom1 = new SecureRandom();
|
SecureRandom secureRandom1 = new SecureRandom();
|
||||||
if(LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
String provider = secureRandom1.getProvider().getName();
|
String provider = secureRandom1.getProvider().getName();
|
||||||
String algorithm = secureRandom1.getAlgorithm();
|
String algorithm = secureRandom1.getAlgorithm();
|
||||||
LOG.info("Default SecureRandom: " + provider + " " + algorithm);
|
LOG.info("Default SecureRandom: " + provider + " " + algorithm);
|
||||||
@@ -168,7 +168,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int[] deriveConfirmationCodes(byte[] secret) {
|
public int[] deriveConfirmationCodes(byte[] secret) {
|
||||||
if(secret.length != SecretKey.LENGTH)
|
if (secret.length != SecretKey.LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
byte[] alice = counterModeKdf(secret, CODE, 0);
|
byte[] alice = counterModeKdf(secret, CODE, 0);
|
||||||
byte[] bob = counterModeKdf(secret, CODE, 1);
|
byte[] bob = counterModeKdf(secret, CODE, 1);
|
||||||
@@ -179,7 +179,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public byte[][] deriveInvitationNonces(byte[] secret) {
|
public byte[][] deriveInvitationNonces(byte[] secret) {
|
||||||
if(secret.length != SecretKey.LENGTH)
|
if (secret.length != SecretKey.LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
byte[] alice = counterModeKdf(secret, NONCE, 0);
|
byte[] alice = counterModeKdf(secret, NONCE, 0);
|
||||||
byte[] bob = counterModeKdf(secret, NONCE, 1);
|
byte[] bob = counterModeKdf(secret, NONCE, 1);
|
||||||
@@ -193,7 +193,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
byte[] ourHash = messageDigest.digest(ourPublicKey);
|
byte[] ourHash = messageDigest.digest(ourPublicKey);
|
||||||
byte[] theirHash = messageDigest.digest(theirPublicKey);
|
byte[] theirHash = messageDigest.digest(theirPublicKey);
|
||||||
byte[] aliceInfo, bobInfo;
|
byte[] aliceInfo, bobInfo;
|
||||||
if(alice) {
|
if (alice) {
|
||||||
aliceInfo = ourHash;
|
aliceInfo = ourHash;
|
||||||
bobInfo = theirHash;
|
bobInfo = theirHash;
|
||||||
} else {
|
} else {
|
||||||
@@ -212,9 +212,9 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
// Package access for testing
|
// Package access for testing
|
||||||
byte[] deriveSharedSecret(PrivateKey priv, PublicKey pub)
|
byte[] deriveSharedSecret(PrivateKey priv, PublicKey pub)
|
||||||
throws GeneralSecurityException {
|
throws GeneralSecurityException {
|
||||||
if(!(priv instanceof Sec1PrivateKey))
|
if (!(priv instanceof Sec1PrivateKey))
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
if(!(pub instanceof Sec1PublicKey))
|
if (!(pub instanceof Sec1PublicKey))
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
ECPrivateKeyParameters ecPriv = ((Sec1PrivateKey) priv).getKey();
|
ECPrivateKeyParameters ecPriv = ((Sec1PrivateKey) priv).getKey();
|
||||||
ECPublicKeyParameters ecPub = ((Sec1PublicKey) pub).getKey();
|
ECPublicKeyParameters ecPub = ((Sec1PublicKey) pub).getKey();
|
||||||
@@ -223,46 +223,46 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
agreement.init(ecPriv);
|
agreement.init(ecPriv);
|
||||||
byte[] secret = agreement.calculateAgreement(ecPub).toByteArray();
|
byte[] secret = agreement.calculateAgreement(ecPub).toByteArray();
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Deriving shared secret took " + duration + " ms");
|
LOG.info("Deriving shared secret took " + duration + " ms");
|
||||||
return secret;
|
return secret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] deriveGroupSalt(byte[] secret) {
|
public byte[] deriveGroupSalt(byte[] secret) {
|
||||||
if(secret.length != SecretKey.LENGTH)
|
if (secret.length != SecretKey.LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
return counterModeKdf(secret, SALT, 0);
|
return counterModeKdf(secret, SALT, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] deriveInitialSecret(byte[] secret, int transportIndex) {
|
public byte[] deriveInitialSecret(byte[] secret, int transportIndex) {
|
||||||
if(secret.length != SecretKey.LENGTH)
|
if (secret.length != SecretKey.LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
if(transportIndex < 0) throw new IllegalArgumentException();
|
if (transportIndex < 0) throw new IllegalArgumentException();
|
||||||
return counterModeKdf(secret, FIRST, transportIndex);
|
return counterModeKdf(secret, FIRST, transportIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] deriveNextSecret(byte[] secret, long period) {
|
public byte[] deriveNextSecret(byte[] secret, long period) {
|
||||||
if(secret.length != SecretKey.LENGTH)
|
if (secret.length != SecretKey.LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
if(period < 0 || period > MAX_32_BIT_UNSIGNED)
|
if (period < 0 || period > MAX_32_BIT_UNSIGNED)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
return counterModeKdf(secret, ROTATE, period);
|
return counterModeKdf(secret, ROTATE, period);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SecretKey deriveTagKey(byte[] secret, boolean alice) {
|
public SecretKey deriveTagKey(byte[] secret, boolean alice) {
|
||||||
if(secret.length != SecretKey.LENGTH)
|
if (secret.length != SecretKey.LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
if(alice) return deriveKey(secret, A_TAG, 0);
|
if (alice) return deriveKey(secret, A_TAG, 0);
|
||||||
else return deriveKey(secret, B_TAG, 0);
|
else return deriveKey(secret, B_TAG, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SecretKey deriveFrameKey(byte[] secret, long streamNumber,
|
public SecretKey deriveFrameKey(byte[] secret, long streamNumber,
|
||||||
boolean alice) {
|
boolean alice) {
|
||||||
if(secret.length != SecretKey.LENGTH)
|
if (secret.length != SecretKey.LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
if(streamNumber < 0 || streamNumber > MAX_32_BIT_UNSIGNED)
|
if (streamNumber < 0 || streamNumber > MAX_32_BIT_UNSIGNED)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
if(alice) return deriveKey(secret, A_FRAME, streamNumber);
|
if (alice) return deriveKey(secret, A_FRAME, streamNumber);
|
||||||
else return deriveKey(secret, B_FRAME, streamNumber);
|
else return deriveKey(secret, B_FRAME, streamNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,10 +271,10 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void encodeTag(byte[] tag, SecretKey tagKey, long streamNumber) {
|
public void encodeTag(byte[] tag, SecretKey tagKey, long streamNumber) {
|
||||||
if(tag.length < TAG_LENGTH) throw new IllegalArgumentException();
|
if (tag.length < TAG_LENGTH) throw new IllegalArgumentException();
|
||||||
if(streamNumber < 0 || streamNumber > MAX_32_BIT_UNSIGNED)
|
if (streamNumber < 0 || streamNumber > MAX_32_BIT_UNSIGNED)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
for(int i = 0; i < TAG_LENGTH; i++) tag[i] = 0;
|
for (int i = 0; i < TAG_LENGTH; i++) tag[i] = 0;
|
||||||
ByteUtils.writeUint32(streamNumber, tag, 0);
|
ByteUtils.writeUint32(streamNumber, tag, 0);
|
||||||
BlockCipher cipher = new AESLightEngine();
|
BlockCipher cipher = new AESLightEngine();
|
||||||
assert cipher.getBlockSize() == TAG_LENGTH;
|
assert cipher.getBlockSize() == TAG_LENGTH;
|
||||||
@@ -308,7 +308,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
int outputOff = salt.length + 4 + iv.length;
|
int outputOff = salt.length + 4 + iv.length;
|
||||||
cipher.process(input, 0, input.length, output, outputOff);
|
cipher.process(input, 0, input.length, output, outputOff);
|
||||||
return output;
|
return output;
|
||||||
} catch(GeneralSecurityException e) {
|
} catch (GeneralSecurityException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -317,12 +317,12 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
AuthenticatedCipher cipher = new AuthenticatedCipherImpl();
|
AuthenticatedCipher cipher = new AuthenticatedCipherImpl();
|
||||||
int macBytes = cipher.getMacBytes();
|
int macBytes = cipher.getMacBytes();
|
||||||
// The input contains the salt, iterations, IV, ciphertext and MAC
|
// The input contains the salt, iterations, IV, ciphertext and MAC
|
||||||
if(input.length < PBKDF_SALT_BYTES + 4 + STORAGE_IV_BYTES + macBytes)
|
if (input.length < PBKDF_SALT_BYTES + 4 + STORAGE_IV_BYTES + macBytes)
|
||||||
return null; // Invalid input
|
return null; // Invalid input
|
||||||
byte[] salt = new byte[PBKDF_SALT_BYTES];
|
byte[] salt = new byte[PBKDF_SALT_BYTES];
|
||||||
System.arraycopy(input, 0, salt, 0, salt.length);
|
System.arraycopy(input, 0, salt, 0, salt.length);
|
||||||
long iterations = ByteUtils.readUint32(input, salt.length);
|
long iterations = ByteUtils.readUint32(input, salt.length);
|
||||||
if(iterations < 0 || iterations > Integer.MAX_VALUE)
|
if (iterations < 0 || iterations > Integer.MAX_VALUE)
|
||||||
return null; // Invalid iteration count
|
return null; // Invalid iteration count
|
||||||
byte[] iv = new byte[STORAGE_IV_BYTES];
|
byte[] iv = new byte[STORAGE_IV_BYTES];
|
||||||
System.arraycopy(input, salt.length + 4, iv, 0, iv.length);
|
System.arraycopy(input, salt.length + 4, iv, 0, iv.length);
|
||||||
@@ -331,7 +331,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
// Initialise the cipher
|
// Initialise the cipher
|
||||||
try {
|
try {
|
||||||
cipher.init(false, key, iv);
|
cipher.init(false, key, iv);
|
||||||
} catch(GeneralSecurityException e) {
|
} catch (GeneralSecurityException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
// Try to decrypt the ciphertext (may be invalid)
|
// Try to decrypt the ciphertext (may be invalid)
|
||||||
@@ -341,7 +341,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
byte[] output = new byte[inputLen - macBytes];
|
byte[] output = new byte[inputLen - macBytes];
|
||||||
cipher.process(input, inputOff, inputLen, output, 0);
|
cipher.process(input, inputOff, inputLen, output, 0);
|
||||||
return output;
|
return output;
|
||||||
} catch(GeneralSecurityException e) {
|
} catch (GeneralSecurityException e) {
|
||||||
return null; // Invalid ciphertext
|
return null; // Invalid ciphertext
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -351,18 +351,18 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
private byte[] concatenationKdf(byte[]... inputs) {
|
private byte[] concatenationKdf(byte[]... inputs) {
|
||||||
// The output of the hash function must be long enough to use as a key
|
// The output of the hash function must be long enough to use as a key
|
||||||
MessageDigest messageDigest = getMessageDigest();
|
MessageDigest messageDigest = getMessageDigest();
|
||||||
if(messageDigest.getDigestLength() < SecretKey.LENGTH)
|
if (messageDigest.getDigestLength() < SecretKey.LENGTH)
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
// Each input is length-prefixed - the length must fit in an
|
// Each input is length-prefixed - the length must fit in an
|
||||||
// unsigned 8-bit integer
|
// unsigned 8-bit integer
|
||||||
for(byte[] input : inputs) {
|
for (byte[] input : inputs) {
|
||||||
if(input.length > 255) throw new IllegalArgumentException();
|
if (input.length > 255) throw new IllegalArgumentException();
|
||||||
messageDigest.update((byte) input.length);
|
messageDigest.update((byte) input.length);
|
||||||
messageDigest.update(input);
|
messageDigest.update(input);
|
||||||
}
|
}
|
||||||
byte[] hash = messageDigest.digest();
|
byte[] hash = messageDigest.digest();
|
||||||
// The output is the first SecretKey.LENGTH bytes of the hash
|
// The output is the first SecretKey.LENGTH bytes of the hash
|
||||||
if(hash.length == SecretKey.LENGTH) return hash;
|
if (hash.length == SecretKey.LENGTH) return hash;
|
||||||
byte[] truncated = new byte[SecretKey.LENGTH];
|
byte[] truncated = new byte[SecretKey.LENGTH];
|
||||||
System.arraycopy(hash, 0, truncated, 0, truncated.length);
|
System.arraycopy(hash, 0, truncated, 0, truncated.length);
|
||||||
return truncated;
|
return truncated;
|
||||||
@@ -371,10 +371,10 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
// Key derivation function based on a PRF in counter mode - see
|
// Key derivation function based on a PRF in counter mode - see
|
||||||
// NIST SP 800-108, section 5.1
|
// NIST SP 800-108, section 5.1
|
||||||
private byte[] counterModeKdf(byte[] secret, byte[] label, long context) {
|
private byte[] counterModeKdf(byte[] secret, byte[] label, long context) {
|
||||||
if(secret.length != SecretKey.LENGTH)
|
if (secret.length != SecretKey.LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
// The label must be null-terminated
|
// The label must be null-terminated
|
||||||
if(label[label.length - 1] != '\0')
|
if (label[label.length - 1] != '\0')
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
// Initialise the PRF
|
// Initialise the PRF
|
||||||
Mac prf = new HMac(new SHA256Digest());
|
Mac prf = new HMac(new SHA256Digest());
|
||||||
@@ -382,7 +382,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
prf.init(k);
|
prf.init(k);
|
||||||
int macLength = prf.getMacSize();
|
int macLength = prf.getMacSize();
|
||||||
// The output of the PRF must be long enough to use as a key
|
// The output of the PRF must be long enough to use as a key
|
||||||
if(macLength < SecretKey.LENGTH) throw new RuntimeException();
|
if (macLength < SecretKey.LENGTH) throw new RuntimeException();
|
||||||
byte[] mac = new byte[macLength];
|
byte[] mac = new byte[macLength];
|
||||||
prf.update((byte) 0); // Counter
|
prf.update((byte) 0); // Counter
|
||||||
prf.update(label, 0, label.length); // Null-terminated
|
prf.update(label, 0, label.length); // Null-terminated
|
||||||
@@ -392,7 +392,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
prf.update((byte) SecretKey.LENGTH); // Output length
|
prf.update((byte) SecretKey.LENGTH); // Output length
|
||||||
prf.doFinal(mac, 0);
|
prf.doFinal(mac, 0);
|
||||||
// The output is the first SecretKey.LENGTH bytes of the MAC
|
// The output is the first SecretKey.LENGTH bytes of the MAC
|
||||||
if(mac.length == SecretKey.LENGTH) return mac;
|
if (mac.length == SecretKey.LENGTH) return mac;
|
||||||
byte[] truncated = new byte[SecretKey.LENGTH];
|
byte[] truncated = new byte[SecretKey.LENGTH];
|
||||||
System.arraycopy(mac, 0, truncated, 0, truncated.length);
|
System.arraycopy(mac, 0, truncated, 0, truncated.length);
|
||||||
return truncated;
|
return truncated;
|
||||||
@@ -414,9 +414,9 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
List<Long> quickSamples = new ArrayList<Long>(PBKDF_SAMPLES);
|
List<Long> quickSamples = new ArrayList<Long>(PBKDF_SAMPLES);
|
||||||
List<Long> slowSamples = new ArrayList<Long>(PBKDF_SAMPLES);
|
List<Long> slowSamples = new ArrayList<Long>(PBKDF_SAMPLES);
|
||||||
long iterationNanos = 0, initNanos = 0;
|
long iterationNanos = 0, initNanos = 0;
|
||||||
while(iterationNanos <= 0 || initNanos <= 0) {
|
while (iterationNanos <= 0 || initNanos <= 0) {
|
||||||
// Sample the running time with one iteration and two iterations
|
// Sample the running time with one iteration and two iterations
|
||||||
for(int i = 0; i < PBKDF_SAMPLES; i++) {
|
for (int i = 0; i < PBKDF_SAMPLES; i++) {
|
||||||
quickSamples.add(sampleRunningTime(1));
|
quickSamples.add(sampleRunningTime(1));
|
||||||
slowSamples.add(sampleRunningTime(2));
|
slowSamples.add(sampleRunningTime(2));
|
||||||
}
|
}
|
||||||
@@ -425,16 +425,16 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
long slowMedian = median(slowSamples);
|
long slowMedian = median(slowSamples);
|
||||||
iterationNanos = slowMedian - quickMedian;
|
iterationNanos = slowMedian - quickMedian;
|
||||||
initNanos = quickMedian - iterationNanos;
|
initNanos = quickMedian - iterationNanos;
|
||||||
if(LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
LOG.info("Init: " + initNanos + ", iteration: "
|
LOG.info("Init: " + initNanos + ", iteration: "
|
||||||
+ iterationNanos);
|
+ iterationNanos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
long targetNanos = targetMillis * 1000L * 1000L;
|
long targetNanos = targetMillis * 1000L * 1000L;
|
||||||
long iterations = (targetNanos - initNanos) / iterationNanos;
|
long iterations = (targetNanos - initNanos) / iterationNanos;
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("Target iterations: " + iterations);
|
if (LOG.isLoggable(INFO)) LOG.info("Target iterations: " + iterations);
|
||||||
if(iterations < 1) return 1;
|
if (iterations < 1) return 1;
|
||||||
if(iterations > Integer.MAX_VALUE) return Integer.MAX_VALUE;
|
if (iterations > Integer.MAX_VALUE) return Integer.MAX_VALUE;
|
||||||
return (int) iterations;
|
return (int) iterations;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -452,9 +452,9 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
|
|
||||||
private long median(List<Long> list) {
|
private long median(List<Long> list) {
|
||||||
int size = list.size();
|
int size = list.size();
|
||||||
if(size == 0) throw new IllegalArgumentException();
|
if (size == 0) throw new IllegalArgumentException();
|
||||||
Collections.sort(list);
|
Collections.sort(list);
|
||||||
if(size % 2 == 1) return list.get(size / 2);
|
if (size % 2 == 1) return list.get(size / 2);
|
||||||
return list.get(size / 2 - 1) + list.get(size / 2) / 2;
|
return list.get(size / 2 - 1) + list.get(size / 2) / 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ class FortunaGenerator {
|
|||||||
synchLock.lock();
|
synchLock.lock();
|
||||||
try {
|
try {
|
||||||
counter[0]++;
|
counter[0]++;
|
||||||
for(int i = 0; counter[i] == 0; i++) {
|
for (int i = 0; counter[i] == 0; i++) {
|
||||||
if(i + 1 == BLOCK_BYTES)
|
if (i + 1 == BLOCK_BYTES)
|
||||||
throw new RuntimeException("Counter exhausted");
|
throw new RuntimeException("Counter exhausted");
|
||||||
counter[i + 1]++;
|
counter[i + 1]++;
|
||||||
}
|
}
|
||||||
@@ -76,31 +76,31 @@ class FortunaGenerator {
|
|||||||
synchLock.lock();
|
synchLock.lock();
|
||||||
try {
|
try {
|
||||||
// Don't write more than the maximum number of bytes in one request
|
// Don't write more than the maximum number of bytes in one request
|
||||||
if(len > MAX_BYTES_PER_REQUEST) len = MAX_BYTES_PER_REQUEST;
|
if (len > MAX_BYTES_PER_REQUEST) len = MAX_BYTES_PER_REQUEST;
|
||||||
cipher.init(true, new KeyParameter(key));
|
cipher.init(true, new KeyParameter(key));
|
||||||
// Generate full blocks directly into the output buffer
|
// Generate full blocks directly into the output buffer
|
||||||
int fullBlocks = len / BLOCK_BYTES;
|
int fullBlocks = len / BLOCK_BYTES;
|
||||||
for(int i = 0; i < fullBlocks; i++) {
|
for (int i = 0; i < fullBlocks; i++) {
|
||||||
cipher.processBlock(counter, 0, dest, off + i * BLOCK_BYTES);
|
cipher.processBlock(counter, 0, dest, off + i * BLOCK_BYTES);
|
||||||
incrementCounter();
|
incrementCounter();
|
||||||
}
|
}
|
||||||
// Generate a partial block if needed
|
// Generate a partial block if needed
|
||||||
int done = fullBlocks * BLOCK_BYTES, remaining = len - done;
|
int done = fullBlocks * BLOCK_BYTES, remaining = len - done;
|
||||||
assert remaining < BLOCK_BYTES;
|
assert remaining < BLOCK_BYTES;
|
||||||
if(remaining > 0) {
|
if (remaining > 0) {
|
||||||
cipher.processBlock(counter, 0, buffer, 0);
|
cipher.processBlock(counter, 0, buffer, 0);
|
||||||
incrementCounter();
|
incrementCounter();
|
||||||
// Copy the partial block to the output buffer and erase our copy
|
// Copy the partial block to the output buffer and erase our copy
|
||||||
System.arraycopy(buffer, 0, dest, off + done, remaining);
|
System.arraycopy(buffer, 0, dest, off + done, remaining);
|
||||||
for(int i = 0; i < BLOCK_BYTES; i++) buffer[i] = 0;
|
for (int i = 0; i < BLOCK_BYTES; i++) buffer[i] = 0;
|
||||||
}
|
}
|
||||||
// Generate a new key
|
// Generate a new key
|
||||||
for(int i = 0; i < KEY_BYTES / BLOCK_BYTES; i++) {
|
for (int i = 0; i < KEY_BYTES / BLOCK_BYTES; i++) {
|
||||||
cipher.processBlock(counter, 0, newKey, i * BLOCK_BYTES);
|
cipher.processBlock(counter, 0, newKey, i * BLOCK_BYTES);
|
||||||
incrementCounter();
|
incrementCounter();
|
||||||
}
|
}
|
||||||
System.arraycopy(newKey, 0, key, 0, KEY_BYTES);
|
System.arraycopy(newKey, 0, key, 0, KEY_BYTES);
|
||||||
for(int i = 0; i < KEY_BYTES; i++) newKey[i] = 0;
|
for (int i = 0; i < KEY_BYTES; i++) newKey[i] = 0;
|
||||||
// Return the number of bytes written
|
// Return the number of bytes written
|
||||||
return len;
|
return len;
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -37,12 +37,12 @@ class FortunaSecureRandom extends SecureRandom {
|
|||||||
SecureRandom r = new FortunaSecureRandom(seed);
|
SecureRandom r = new FortunaSecureRandom(seed);
|
||||||
byte[] output = new byte[16];
|
byte[] output = new byte[16];
|
||||||
r.nextBytes(output);
|
r.nextBytes(output);
|
||||||
if(!Arrays.equals(SELF_TEST_VECTOR_1, output)) return false;
|
if (!Arrays.equals(SELF_TEST_VECTOR_1, output)) return false;
|
||||||
r.nextBytes(output);
|
r.nextBytes(output);
|
||||||
if(!Arrays.equals(SELF_TEST_VECTOR_2, output)) return false;
|
if (!Arrays.equals(SELF_TEST_VECTOR_2, output)) return false;
|
||||||
r.setSeed(seed);
|
r.setSeed(seed);
|
||||||
r.nextBytes(output);
|
r.nextBytes(output);
|
||||||
if(!Arrays.equals(SELF_TEST_VECTOR_3, output)) return false;
|
if (!Arrays.equals(SELF_TEST_VECTOR_3, output)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ class FortunaSecureRandom extends SecureRandom {
|
|||||||
@Override
|
@Override
|
||||||
protected void engineNextBytes(byte[] b) {
|
protected void engineNextBytes(byte[] b) {
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
while(offset < b.length)
|
while (offset < b.length)
|
||||||
offset += generator.nextBytes(b, offset, b.length - offset);
|
offset += generator.nextBytes(b, offset, b.length - offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,39 +10,39 @@ import org.briarproject.util.ByteUtils;
|
|||||||
class FrameEncoder {
|
class FrameEncoder {
|
||||||
|
|
||||||
static void encodeIv(byte[] iv, long frameNumber, boolean header) {
|
static void encodeIv(byte[] iv, long frameNumber, boolean header) {
|
||||||
if(iv.length < IV_LENGTH) throw new IllegalArgumentException();
|
if (iv.length < IV_LENGTH) throw new IllegalArgumentException();
|
||||||
if(frameNumber < 0 || frameNumber > MAX_32_BIT_UNSIGNED)
|
if (frameNumber < 0 || frameNumber > MAX_32_BIT_UNSIGNED)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
ByteUtils.writeUint32(frameNumber, iv, 0);
|
ByteUtils.writeUint32(frameNumber, iv, 0);
|
||||||
if(header) iv[4] = 1;
|
if (header) iv[4] = 1;
|
||||||
else iv[4] = 0;
|
else iv[4] = 0;
|
||||||
for(int i = 5; i < IV_LENGTH; i++) iv[i] = 0;
|
for (int i = 5; i < IV_LENGTH; i++) iv[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void encodeHeader(byte[] header, boolean finalFrame,
|
static void encodeHeader(byte[] header, boolean finalFrame,
|
||||||
int payloadLength, int paddingLength) {
|
int payloadLength, int paddingLength) {
|
||||||
if(header.length < HEADER_LENGTH) throw new IllegalArgumentException();
|
if (header.length < HEADER_LENGTH) throw new IllegalArgumentException();
|
||||||
if(payloadLength < 0) throw new IllegalArgumentException();
|
if (payloadLength < 0) throw new IllegalArgumentException();
|
||||||
if(paddingLength < 0) throw new IllegalArgumentException();
|
if (paddingLength < 0) throw new IllegalArgumentException();
|
||||||
if(payloadLength + paddingLength > MAX_PAYLOAD_LENGTH)
|
if (payloadLength + paddingLength > MAX_PAYLOAD_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
ByteUtils.writeUint16(payloadLength, header, 0);
|
ByteUtils.writeUint16(payloadLength, header, 0);
|
||||||
ByteUtils.writeUint16(paddingLength, header, 2);
|
ByteUtils.writeUint16(paddingLength, header, 2);
|
||||||
if(finalFrame) header[0] |= 0x80;
|
if (finalFrame) header[0] |= 0x80;
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean isFinalFrame(byte[] header) {
|
static boolean isFinalFrame(byte[] header) {
|
||||||
if(header.length < HEADER_LENGTH) throw new IllegalArgumentException();
|
if (header.length < HEADER_LENGTH) throw new IllegalArgumentException();
|
||||||
return (header[0] & 0x80) == 0x80;
|
return (header[0] & 0x80) == 0x80;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getPayloadLength(byte[] header) {
|
static int getPayloadLength(byte[] header) {
|
||||||
if(header.length < HEADER_LENGTH) throw new IllegalArgumentException();
|
if (header.length < HEADER_LENGTH) throw new IllegalArgumentException();
|
||||||
return ByteUtils.readUint16(header, 0) & 0x7FFF;
|
return ByteUtils.readUint16(header, 0) & 0x7FFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getPaddingLength(byte[] header) {
|
static int getPaddingLength(byte[] header) {
|
||||||
if(header.length < HEADER_LENGTH) throw new IllegalArgumentException();
|
if (header.length < HEADER_LENGTH) throw new IllegalArgumentException();
|
||||||
return ByteUtils.readUint16(header, 2);
|
return ByteUtils.readUint16(header, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,19 +16,19 @@ class PasswordStrengthEstimatorImpl implements PasswordStrengthEstimator {
|
|||||||
public float estimateStrength(String password) {
|
public float estimateStrength(String password) {
|
||||||
HashSet<Character> unique = new HashSet<Character>();
|
HashSet<Character> unique = new HashSet<Character>();
|
||||||
int length = password.length();
|
int length = password.length();
|
||||||
for(int i = 0; i < length; i++) unique.add(password.charAt(i));
|
for (int i = 0; i < length; i++) unique.add(password.charAt(i));
|
||||||
boolean lower = false, upper = false, digit = false, other = false;
|
boolean lower = false, upper = false, digit = false, other = false;
|
||||||
for(char c : unique) {
|
for (char c : unique) {
|
||||||
if(Character.isLowerCase(c)) lower = true;
|
if (Character.isLowerCase(c)) lower = true;
|
||||||
else if(Character.isUpperCase(c)) upper = true;
|
else if (Character.isUpperCase(c)) upper = true;
|
||||||
else if(Character.isDigit(c)) digit = true;
|
else if (Character.isDigit(c)) digit = true;
|
||||||
else other = true;
|
else other = true;
|
||||||
}
|
}
|
||||||
int alphabetSize = 0;
|
int alphabetSize = 0;
|
||||||
if(lower) alphabetSize += LOWER;
|
if (lower) alphabetSize += LOWER;
|
||||||
if(upper) alphabetSize += UPPER;
|
if (upper) alphabetSize += UPPER;
|
||||||
if(digit) alphabetSize += DIGIT;
|
if (digit) alphabetSize += DIGIT;
|
||||||
if(other) alphabetSize += OTHER;
|
if (other) alphabetSize += OTHER;
|
||||||
double score = Math.log(Math.pow(alphabetSize, unique.size()));
|
double score = Math.log(Math.pow(alphabetSize, unique.size()));
|
||||||
return Math.min(1, (float) (score / STRONG));
|
return Math.min(1, (float) (score / STRONG));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class PseudoRandomImpl implements PseudoRandom {
|
|||||||
public byte[] nextBytes(int length) {
|
public byte[] nextBytes(int length) {
|
||||||
byte[] b = new byte[length];
|
byte[] b = new byte[length];
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
while(offset < length) offset += generator.nextBytes(b, offset, length);
|
while (offset < length) offset += generator.nextBytes(b, offset, length);
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,39 +43,39 @@ class Sec1KeyParser implements KeyParser {
|
|||||||
// The validation procedure comes from SEC 1, section 3.2.2.1. Note
|
// The validation procedure comes from SEC 1, section 3.2.2.1. Note
|
||||||
// that SEC 1 parameter names are used below, not RFC 5639 names
|
// that SEC 1 parameter names are used below, not RFC 5639 names
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
if(encodedKey.length != publicKeyBytes)
|
if (encodedKey.length != publicKeyBytes)
|
||||||
throw new GeneralSecurityException();
|
throw new GeneralSecurityException();
|
||||||
// The first byte must be 0x04
|
// The first byte must be 0x04
|
||||||
if(encodedKey[0] != 4) throw new GeneralSecurityException();
|
if (encodedKey[0] != 4) throw new GeneralSecurityException();
|
||||||
// The x co-ordinate must be >= 0 and < p
|
// The x co-ordinate must be >= 0 and < p
|
||||||
byte[] xBytes = new byte[bytesPerInt];
|
byte[] xBytes = new byte[bytesPerInt];
|
||||||
System.arraycopy(encodedKey, 1, xBytes, 0, bytesPerInt);
|
System.arraycopy(encodedKey, 1, xBytes, 0, bytesPerInt);
|
||||||
BigInteger x = new BigInteger(1, xBytes); // Positive signum
|
BigInteger x = new BigInteger(1, xBytes); // Positive signum
|
||||||
if(x.compareTo(modulus) >= 0) throw new GeneralSecurityException();
|
if (x.compareTo(modulus) >= 0) throw new GeneralSecurityException();
|
||||||
// The y co-ordinate must be >= 0 and < p
|
// The y co-ordinate must be >= 0 and < p
|
||||||
byte[] yBytes = new byte[bytesPerInt];
|
byte[] yBytes = new byte[bytesPerInt];
|
||||||
System.arraycopy(encodedKey, 1 + bytesPerInt, yBytes, 0, bytesPerInt);
|
System.arraycopy(encodedKey, 1 + bytesPerInt, yBytes, 0, bytesPerInt);
|
||||||
BigInteger y = new BigInteger(1, yBytes); // Positive signum
|
BigInteger y = new BigInteger(1, yBytes); // Positive signum
|
||||||
if(y.compareTo(modulus) >= 0) throw new GeneralSecurityException();
|
if (y.compareTo(modulus) >= 0) throw new GeneralSecurityException();
|
||||||
// Verify that y^2 == x^3 + ax + b (mod p)
|
// Verify that y^2 == x^3 + ax + b (mod p)
|
||||||
ECCurve curve = params.getCurve();
|
ECCurve curve = params.getCurve();
|
||||||
BigInteger a = curve.getA().toBigInteger();
|
BigInteger a = curve.getA().toBigInteger();
|
||||||
BigInteger b = curve.getB().toBigInteger();
|
BigInteger b = curve.getB().toBigInteger();
|
||||||
BigInteger lhs = y.multiply(y).mod(modulus);
|
BigInteger lhs = y.multiply(y).mod(modulus);
|
||||||
BigInteger rhs = x.multiply(x).add(a).multiply(x).add(b).mod(modulus);
|
BigInteger rhs = x.multiply(x).add(a).multiply(x).add(b).mod(modulus);
|
||||||
if(!lhs.equals(rhs)) throw new GeneralSecurityException();
|
if (!lhs.equals(rhs)) throw new GeneralSecurityException();
|
||||||
// We know the point (x, y) is on the curve, so we can create the point
|
// We know the point (x, y) is on the curve, so we can create the point
|
||||||
ECPoint pub = curve.createPoint(x, y).normalize();
|
ECPoint pub = curve.createPoint(x, y).normalize();
|
||||||
// Verify that the point (x, y) is not the point at infinity
|
// Verify that the point (x, y) is not the point at infinity
|
||||||
if(pub.isInfinity()) throw new GeneralSecurityException();
|
if (pub.isInfinity()) throw new GeneralSecurityException();
|
||||||
// Verify that the point (x, y) times n is the point at infinity
|
// Verify that the point (x, y) times n is the point at infinity
|
||||||
if(!pub.multiply(params.getN()).isInfinity())
|
if (!pub.multiply(params.getN()).isInfinity())
|
||||||
throw new GeneralSecurityException();
|
throw new GeneralSecurityException();
|
||||||
// Construct a public key from the point (x, y) and the params
|
// Construct a public key from the point (x, y) and the params
|
||||||
ECPublicKeyParameters k = new ECPublicKeyParameters(pub, params);
|
ECPublicKeyParameters k = new ECPublicKeyParameters(pub, params);
|
||||||
PublicKey p = new Sec1PublicKey(k, keyBits);
|
PublicKey p = new Sec1PublicKey(k, keyBits);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Parsing public key took " + duration + " ms");
|
LOG.info("Parsing public key took " + duration + " ms");
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@@ -83,17 +83,17 @@ class Sec1KeyParser implements KeyParser {
|
|||||||
public PrivateKey parsePrivateKey(byte[] encodedKey)
|
public PrivateKey parsePrivateKey(byte[] encodedKey)
|
||||||
throws GeneralSecurityException {
|
throws GeneralSecurityException {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
if(encodedKey.length != privateKeyBytes)
|
if (encodedKey.length != privateKeyBytes)
|
||||||
throw new GeneralSecurityException();
|
throw new GeneralSecurityException();
|
||||||
BigInteger d = new BigInteger(1, encodedKey); // Positive signum
|
BigInteger d = new BigInteger(1, encodedKey); // Positive signum
|
||||||
// Verify that the private value is < n
|
// Verify that the private value is < n
|
||||||
if(d.compareTo(params.getN()) >= 0)
|
if (d.compareTo(params.getN()) >= 0)
|
||||||
throw new GeneralSecurityException();
|
throw new GeneralSecurityException();
|
||||||
// Construct a private key from the private value and the params
|
// Construct a private key from the private value and the params
|
||||||
ECPrivateKeyParameters k = new ECPrivateKeyParameters(d, params);
|
ECPrivateKeyParameters k = new ECPrivateKeyParameters(d, params);
|
||||||
PrivateKey p = new Sec1PrivateKey(k, keyBits);
|
PrivateKey p = new Sec1PrivateKey(k, keyBits);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Parsing private key took " + duration + " ms");
|
LOG.info("Parsing private key took " + duration + " ms");
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ class Sec1Utils {
|
|||||||
|
|
||||||
static void convertToFixedLength(byte[] src, byte[] dest, int destOff,
|
static void convertToFixedLength(byte[] src, byte[] dest, int destOff,
|
||||||
int destLen) {
|
int destLen) {
|
||||||
if(src.length < destLen) {
|
if (src.length < destLen) {
|
||||||
int padding = destLen - src.length;
|
int padding = destLen - src.length;
|
||||||
for(int i = destOff; i < destOff + padding; i++) dest[i] = 0;
|
for (int i = destOff; i < destOff + padding; i++) dest[i] = 0;
|
||||||
System.arraycopy(src, 0, dest, destOff + padding, src.length);
|
System.arraycopy(src, 0, dest, destOff + padding, src.length);
|
||||||
} else {
|
} else {
|
||||||
int srcOff = src.length - destLen;
|
int srcOff = src.length - destLen;
|
||||||
|
|||||||
@@ -35,13 +35,13 @@ class SignatureImpl implements Signature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void initSign(PrivateKey k) throws GeneralSecurityException {
|
public void initSign(PrivateKey k) throws GeneralSecurityException {
|
||||||
if(!(k instanceof Sec1PrivateKey)) throw new GeneralSecurityException();
|
if (!(k instanceof Sec1PrivateKey)) throw new GeneralSecurityException();
|
||||||
ECPrivateKeyParameters priv = ((Sec1PrivateKey) k).getKey();
|
ECPrivateKeyParameters priv = ((Sec1PrivateKey) k).getKey();
|
||||||
signer.init(true, new ParametersWithRandom(priv, secureRandom));
|
signer.init(true, new ParametersWithRandom(priv, secureRandom));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initVerify(PublicKey k) throws GeneralSecurityException {
|
public void initVerify(PublicKey k) throws GeneralSecurityException {
|
||||||
if(!(k instanceof Sec1PublicKey)) throw new GeneralSecurityException();
|
if (!(k instanceof Sec1PublicKey)) throw new GeneralSecurityException();
|
||||||
ECPublicKeyParameters pub = ((Sec1PublicKey) k).getKey();
|
ECPublicKeyParameters pub = ((Sec1PublicKey) k).getKey();
|
||||||
signer.init(false, pub);
|
signer.init(false, pub);
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ class SignatureImpl implements Signature {
|
|||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
byte[] signature = signer.generateSignature();
|
byte[] signature = signer.generateSignature();
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Generating signature took " + duration + " ms");
|
LOG.info("Generating signature took " + duration + " ms");
|
||||||
return signature;
|
return signature;
|
||||||
}
|
}
|
||||||
@@ -71,7 +71,7 @@ class SignatureImpl implements Signature {
|
|||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
boolean valid = signer.verifySignature(signature);
|
boolean valid = signer.verifySignature(signature);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Verifying signature took " + duration + " ms");
|
LOG.info("Verifying signature took " + duration + " ms");
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,14 +38,14 @@ class StreamDecrypterImpl implements StreamDecrypter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int readFrame(byte[] payload) throws IOException {
|
public int readFrame(byte[] payload) throws IOException {
|
||||||
if(payload.length < MAX_PAYLOAD_LENGTH)
|
if (payload.length < MAX_PAYLOAD_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
if(finalFrame) return -1;
|
if (finalFrame) return -1;
|
||||||
// Read the header
|
// Read the header
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
while(offset < HEADER_LENGTH) {
|
while (offset < HEADER_LENGTH) {
|
||||||
int read = in.read(ciphertext, offset, HEADER_LENGTH - offset);
|
int read = in.read(ciphertext, offset, HEADER_LENGTH - offset);
|
||||||
if(read == -1) throw new EOFException();
|
if (read == -1) throw new EOFException();
|
||||||
offset += read;
|
offset += read;
|
||||||
}
|
}
|
||||||
// Decrypt and authenticate the header
|
// Decrypt and authenticate the header
|
||||||
@@ -54,23 +54,23 @@ class StreamDecrypterImpl implements StreamDecrypter {
|
|||||||
frameCipher.init(false, frameKey, iv);
|
frameCipher.init(false, frameKey, iv);
|
||||||
int decrypted = frameCipher.process(ciphertext, 0, HEADER_LENGTH,
|
int decrypted = frameCipher.process(ciphertext, 0, HEADER_LENGTH,
|
||||||
header, 0);
|
header, 0);
|
||||||
if(decrypted != HEADER_LENGTH - MAC_LENGTH)
|
if (decrypted != HEADER_LENGTH - MAC_LENGTH)
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
} catch(GeneralSecurityException e) {
|
} catch (GeneralSecurityException e) {
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
// Decode and validate the header
|
// Decode and validate the header
|
||||||
finalFrame = FrameEncoder.isFinalFrame(header);
|
finalFrame = FrameEncoder.isFinalFrame(header);
|
||||||
int payloadLength = FrameEncoder.getPayloadLength(header);
|
int payloadLength = FrameEncoder.getPayloadLength(header);
|
||||||
int paddingLength = FrameEncoder.getPaddingLength(header);
|
int paddingLength = FrameEncoder.getPaddingLength(header);
|
||||||
if(payloadLength + paddingLength > MAX_PAYLOAD_LENGTH)
|
if (payloadLength + paddingLength > MAX_PAYLOAD_LENGTH)
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
// Read the payload and padding
|
// Read the payload and padding
|
||||||
int frameLength = HEADER_LENGTH + payloadLength + paddingLength
|
int frameLength = HEADER_LENGTH + payloadLength + paddingLength
|
||||||
+ MAC_LENGTH;
|
+ MAC_LENGTH;
|
||||||
while(offset < frameLength) {
|
while (offset < frameLength) {
|
||||||
int read = in.read(ciphertext, offset, frameLength - offset);
|
int read = in.read(ciphertext, offset, frameLength - offset);
|
||||||
if(read == -1) throw new EOFException();
|
if (read == -1) throw new EOFException();
|
||||||
offset += read;
|
offset += read;
|
||||||
}
|
}
|
||||||
// Decrypt and authenticate the payload and padding
|
// Decrypt and authenticate the payload and padding
|
||||||
@@ -79,14 +79,14 @@ class StreamDecrypterImpl implements StreamDecrypter {
|
|||||||
frameCipher.init(false, frameKey, iv);
|
frameCipher.init(false, frameKey, iv);
|
||||||
int decrypted = frameCipher.process(ciphertext, HEADER_LENGTH,
|
int decrypted = frameCipher.process(ciphertext, HEADER_LENGTH,
|
||||||
payloadLength + paddingLength + MAC_LENGTH, payload, 0);
|
payloadLength + paddingLength + MAC_LENGTH, payload, 0);
|
||||||
if(decrypted != payloadLength + paddingLength)
|
if (decrypted != payloadLength + paddingLength)
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
} catch(GeneralSecurityException e) {
|
} catch (GeneralSecurityException e) {
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
// If there's any padding it must be all zeroes
|
// If there's any padding it must be all zeroes
|
||||||
for(int i = 0; i < paddingLength; i++)
|
for (int i = 0; i < paddingLength; i++)
|
||||||
if(payload[payloadLength + i] != 0) throw new FormatException();
|
if (payload[payloadLength + i] != 0) throw new FormatException();
|
||||||
frameNumber++;
|
frameNumber++;
|
||||||
return payloadLength;
|
return payloadLength;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,12 +39,12 @@ class StreamEncrypterImpl implements StreamEncrypter {
|
|||||||
|
|
||||||
public void writeFrame(byte[] payload, int payloadLength,
|
public void writeFrame(byte[] payload, int payloadLength,
|
||||||
int paddingLength, boolean finalFrame) throws IOException {
|
int paddingLength, boolean finalFrame) throws IOException {
|
||||||
if(payloadLength + paddingLength > MAX_PAYLOAD_LENGTH)
|
if (payloadLength + paddingLength > MAX_PAYLOAD_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
// Don't allow the frame counter to wrap
|
// Don't allow the frame counter to wrap
|
||||||
if(frameNumber > MAX_32_BIT_UNSIGNED) throw new IOException();
|
if (frameNumber > MAX_32_BIT_UNSIGNED) throw new IOException();
|
||||||
// Write the tag if required
|
// Write the tag if required
|
||||||
if(writeTag) {
|
if (writeTag) {
|
||||||
out.write(tag, 0, tag.length);
|
out.write(tag, 0, tag.length);
|
||||||
writeTag = false;
|
writeTag = false;
|
||||||
}
|
}
|
||||||
@@ -57,13 +57,13 @@ class StreamEncrypterImpl implements StreamEncrypter {
|
|||||||
frameCipher.init(true, frameKey, iv);
|
frameCipher.init(true, frameKey, iv);
|
||||||
int encrypted = frameCipher.process(plaintext, 0,
|
int encrypted = frameCipher.process(plaintext, 0,
|
||||||
HEADER_LENGTH - MAC_LENGTH, ciphertext, 0);
|
HEADER_LENGTH - MAC_LENGTH, ciphertext, 0);
|
||||||
if(encrypted != HEADER_LENGTH) throw new RuntimeException();
|
if (encrypted != HEADER_LENGTH) throw new RuntimeException();
|
||||||
} catch(GeneralSecurityException badCipher) {
|
} catch (GeneralSecurityException badCipher) {
|
||||||
throw new RuntimeException(badCipher);
|
throw new RuntimeException(badCipher);
|
||||||
}
|
}
|
||||||
// Combine the payload and padding
|
// Combine the payload and padding
|
||||||
System.arraycopy(payload, 0, plaintext, HEADER_LENGTH, payloadLength);
|
System.arraycopy(payload, 0, plaintext, HEADER_LENGTH, payloadLength);
|
||||||
for(int i = 0; i < paddingLength; i++)
|
for (int i = 0; i < paddingLength; i++)
|
||||||
plaintext[HEADER_LENGTH + payloadLength + i] = 0;
|
plaintext[HEADER_LENGTH + payloadLength + i] = 0;
|
||||||
// Encrypt and authenticate the payload and padding
|
// Encrypt and authenticate the payload and padding
|
||||||
FrameEncoder.encodeIv(iv, frameNumber, false);
|
FrameEncoder.encodeIv(iv, frameNumber, false);
|
||||||
@@ -71,9 +71,9 @@ class StreamEncrypterImpl implements StreamEncrypter {
|
|||||||
frameCipher.init(true, frameKey, iv);
|
frameCipher.init(true, frameKey, iv);
|
||||||
int encrypted = frameCipher.process(plaintext, HEADER_LENGTH,
|
int encrypted = frameCipher.process(plaintext, HEADER_LENGTH,
|
||||||
payloadLength + paddingLength, ciphertext, HEADER_LENGTH);
|
payloadLength + paddingLength, ciphertext, HEADER_LENGTH);
|
||||||
if(encrypted != payloadLength + paddingLength + MAC_LENGTH)
|
if (encrypted != payloadLength + paddingLength + MAC_LENGTH)
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
} catch(GeneralSecurityException badCipher) {
|
} catch (GeneralSecurityException badCipher) {
|
||||||
throw new RuntimeException(badCipher);
|
throw new RuntimeException(badCipher);
|
||||||
}
|
}
|
||||||
// Write the frame
|
// Write the frame
|
||||||
@@ -84,7 +84,7 @@ class StreamEncrypterImpl implements StreamEncrypter {
|
|||||||
|
|
||||||
public void flush() throws IOException {
|
public void flush() throws IOException {
|
||||||
// Write the tag if required
|
// Write the tag if required
|
||||||
if(writeTag) {
|
if (writeTag) {
|
||||||
out.write(tag, 0, tag.length);
|
out.write(tag, 0, tag.length);
|
||||||
writeTag = false;
|
writeTag = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class ReaderImpl implements Reader {
|
|||||||
assert !hasLookahead;
|
assert !hasLookahead;
|
||||||
// Read a lookahead byte
|
// Read a lookahead byte
|
||||||
int i = in.read();
|
int i = in.read();
|
||||||
if(i == -1) {
|
if (i == -1) {
|
||||||
eof = true;
|
eof = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -58,49 +58,49 @@ class ReaderImpl implements Reader {
|
|||||||
|
|
||||||
private void consumeLookahead() throws IOException {
|
private void consumeLookahead() throws IOException {
|
||||||
assert hasLookahead;
|
assert hasLookahead;
|
||||||
for(Consumer c : consumers) c.write(next);
|
for (Consumer c : consumers) c.write(next);
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readIntoBuffer(byte[] b, int length, boolean consume)
|
private void readIntoBuffer(byte[] b, int length, boolean consume)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
while(offset < length) {
|
while (offset < length) {
|
||||||
int read = in.read(b, offset, length - offset);
|
int read = in.read(b, offset, length - offset);
|
||||||
if(read == -1) throw new FormatException();
|
if (read == -1) throw new FormatException();
|
||||||
offset += read;
|
offset += read;
|
||||||
}
|
}
|
||||||
if(consume) for(Consumer c : consumers) c.write(b, 0, length);
|
if (consume) for (Consumer c : consumers) c.write(b, 0, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readIntoBuffer(int length, boolean consume)
|
private void readIntoBuffer(int length, boolean consume)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if(buf.length < length) buf = new byte[length];
|
if (buf.length < length) buf = new byte[length];
|
||||||
readIntoBuffer(buf, length, consume);
|
readIntoBuffer(buf, length, consume);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void skip(int length) throws IOException {
|
private void skip(int length) throws IOException {
|
||||||
while(length > 0) {
|
while (length > 0) {
|
||||||
int read = in.read(buf, 0, Math.min(length, buf.length));
|
int read = in.read(buf, 0, Math.min(length, buf.length));
|
||||||
if(read == -1) throw new FormatException();
|
if (read == -1) throw new FormatException();
|
||||||
length -= read;
|
length -= read;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void skipObject() throws IOException {
|
private void skipObject() throws IOException {
|
||||||
if(hasBoolean()) skipBoolean();
|
if (hasBoolean()) skipBoolean();
|
||||||
else if(hasInteger()) skipInteger();
|
else if (hasInteger()) skipInteger();
|
||||||
else if(hasFloat()) skipFloat();
|
else if (hasFloat()) skipFloat();
|
||||||
else if(hasString()) skipString();
|
else if (hasString()) skipString();
|
||||||
else if(hasRaw()) skipRaw();
|
else if (hasRaw()) skipRaw();
|
||||||
else if(hasList()) skipList();
|
else if (hasList()) skipList();
|
||||||
else if(hasMap()) skipMap();
|
else if (hasMap()) skipMap();
|
||||||
else if(hasNull()) skipNull();
|
else if (hasNull()) skipNull();
|
||||||
else throw new FormatException();
|
else throw new FormatException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean eof() throws IOException {
|
public boolean eof() throws IOException {
|
||||||
if(!hasLookahead) readLookahead();
|
if (!hasLookahead) readLookahead();
|
||||||
return eof;
|
return eof;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,56 +113,56 @@ class ReaderImpl implements Reader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void removeConsumer(Consumer c) {
|
public void removeConsumer(Consumer c) {
|
||||||
if(!consumers.remove(c)) throw new IllegalArgumentException();
|
if (!consumers.remove(c)) throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasNull() throws IOException {
|
public boolean hasNull() throws IOException {
|
||||||
if(!hasLookahead) readLookahead();
|
if (!hasLookahead) readLookahead();
|
||||||
if(eof) return false;
|
if (eof) return false;
|
||||||
return next == NULL;
|
return next == NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readNull() throws IOException {
|
public void readNull() throws IOException {
|
||||||
if(!hasNull()) throw new FormatException();
|
if (!hasNull()) throw new FormatException();
|
||||||
consumeLookahead();
|
consumeLookahead();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void skipNull() throws IOException {
|
public void skipNull() throws IOException {
|
||||||
if(!hasNull()) throw new FormatException();
|
if (!hasNull()) throw new FormatException();
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasBoolean() throws IOException {
|
public boolean hasBoolean() throws IOException {
|
||||||
if(!hasLookahead) readLookahead();
|
if (!hasLookahead) readLookahead();
|
||||||
if(eof) return false;
|
if (eof) return false;
|
||||||
return next == FALSE || next == TRUE;
|
return next == FALSE || next == TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean readBoolean() throws IOException {
|
public boolean readBoolean() throws IOException {
|
||||||
if(!hasBoolean()) throw new FormatException();
|
if (!hasBoolean()) throw new FormatException();
|
||||||
boolean bool = next == TRUE;
|
boolean bool = next == TRUE;
|
||||||
consumeLookahead();
|
consumeLookahead();
|
||||||
return bool;
|
return bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void skipBoolean() throws IOException {
|
public void skipBoolean() throws IOException {
|
||||||
if(!hasBoolean()) throw new FormatException();
|
if (!hasBoolean()) throw new FormatException();
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasInteger() throws IOException {
|
public boolean hasInteger() throws IOException {
|
||||||
if(!hasLookahead) readLookahead();
|
if (!hasLookahead) readLookahead();
|
||||||
if(eof) return false;
|
if (eof) return false;
|
||||||
return next == INT_8 || next == INT_16 || next == INT_32 ||
|
return next == INT_8 || next == INT_16 || next == INT_32 ||
|
||||||
next == INT_64;
|
next == INT_64;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long readInteger() throws IOException {
|
public long readInteger() throws IOException {
|
||||||
if(!hasInteger()) throw new FormatException();
|
if (!hasInteger()) throw new FormatException();
|
||||||
consumeLookahead();
|
consumeLookahead();
|
||||||
if(next == INT_8) return readInt8(true);
|
if (next == INT_8) return readInt8(true);
|
||||||
if(next == INT_16) return readInt16(true);
|
if (next == INT_16) return readInt16(true);
|
||||||
if(next == INT_32) return readInt32(true);
|
if (next == INT_32) return readInt32(true);
|
||||||
return readInt64(true);
|
return readInt64(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,7 +174,7 @@ class ReaderImpl implements Reader {
|
|||||||
private short readInt16(boolean consume) throws IOException {
|
private short readInt16(boolean consume) throws IOException {
|
||||||
readIntoBuffer(2, consume);
|
readIntoBuffer(2, consume);
|
||||||
short value = (short) (((buf[0] & 0xFF) << 8) + (buf[1] & 0xFF));
|
short value = (short) (((buf[0] & 0xFF) << 8) + (buf[1] & 0xFF));
|
||||||
if(value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE)
|
if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE)
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@@ -182,8 +182,8 @@ class ReaderImpl implements Reader {
|
|||||||
private int readInt32(boolean consume) throws IOException {
|
private int readInt32(boolean consume) throws IOException {
|
||||||
readIntoBuffer(4, consume);
|
readIntoBuffer(4, consume);
|
||||||
int value = 0;
|
int value = 0;
|
||||||
for(int i = 0; i < 4; i++) value |= (buf[i] & 0xFF) << (24 - i * 8);
|
for (int i = 0; i < 4; i++) value |= (buf[i] & 0xFF) << (24 - i * 8);
|
||||||
if(value >= Short.MIN_VALUE && value <= Short.MAX_VALUE)
|
if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE)
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@@ -191,113 +191,113 @@ class ReaderImpl implements Reader {
|
|||||||
private long readInt64(boolean consume) throws IOException {
|
private long readInt64(boolean consume) throws IOException {
|
||||||
readIntoBuffer(8, consume);
|
readIntoBuffer(8, consume);
|
||||||
long value = 0;
|
long value = 0;
|
||||||
for(int i = 0; i < 8; i++) value |= (buf[i] & 0xFFL) << (56 - i * 8);
|
for (int i = 0; i < 8; i++) value |= (buf[i] & 0xFFL) << (56 - i * 8);
|
||||||
if(value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE)
|
if (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE)
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void skipInteger() throws IOException {
|
public void skipInteger() throws IOException {
|
||||||
if(!hasInteger()) throw new FormatException();
|
if (!hasInteger()) throw new FormatException();
|
||||||
if(next == INT_8) skip(1);
|
if (next == INT_8) skip(1);
|
||||||
else if(next == INT_16) skip(2);
|
else if (next == INT_16) skip(2);
|
||||||
else if(next == INT_32) skip(4);
|
else if (next == INT_32) skip(4);
|
||||||
else skip(8);
|
else skip(8);
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasFloat() throws IOException {
|
public boolean hasFloat() throws IOException {
|
||||||
if(!hasLookahead) readLookahead();
|
if (!hasLookahead) readLookahead();
|
||||||
if(eof) return false;
|
if (eof) return false;
|
||||||
return next == FLOAT_64;
|
return next == FLOAT_64;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double readFloat() throws IOException {
|
public double readFloat() throws IOException {
|
||||||
if(!hasFloat()) throw new FormatException();
|
if (!hasFloat()) throw new FormatException();
|
||||||
consumeLookahead();
|
consumeLookahead();
|
||||||
readIntoBuffer(8, true);
|
readIntoBuffer(8, true);
|
||||||
long value = 0;
|
long value = 0;
|
||||||
for(int i = 0; i < 8; i++) value |= (buf[i] & 0xFFL) << (56 - i * 8);
|
for (int i = 0; i < 8; i++) value |= (buf[i] & 0xFFL) << (56 - i * 8);
|
||||||
return Double.longBitsToDouble(value);
|
return Double.longBitsToDouble(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void skipFloat() throws IOException {
|
public void skipFloat() throws IOException {
|
||||||
if(!hasFloat()) throw new FormatException();
|
if (!hasFloat()) throw new FormatException();
|
||||||
skip(8);
|
skip(8);
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasString() throws IOException {
|
public boolean hasString() throws IOException {
|
||||||
if(!hasLookahead) readLookahead();
|
if (!hasLookahead) readLookahead();
|
||||||
if(eof) return false;
|
if (eof) return false;
|
||||||
return next == STRING_8 || next == STRING_16 || next == STRING_32;
|
return next == STRING_8 || next == STRING_16 || next == STRING_32;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String readString(int maxLength) throws IOException {
|
public String readString(int maxLength) throws IOException {
|
||||||
if(!hasString()) throw new FormatException();
|
if (!hasString()) throw new FormatException();
|
||||||
consumeLookahead();
|
consumeLookahead();
|
||||||
int length = readStringLength(true);
|
int length = readStringLength(true);
|
||||||
if(length < 0 || length > maxLength) throw new FormatException();
|
if (length < 0 || length > maxLength) throw new FormatException();
|
||||||
if(length == 0) return "";
|
if (length == 0) return "";
|
||||||
readIntoBuffer(length, true);
|
readIntoBuffer(length, true);
|
||||||
return new String(buf, 0, length, "UTF-8");
|
return new String(buf, 0, length, "UTF-8");
|
||||||
}
|
}
|
||||||
|
|
||||||
private int readStringLength(boolean consume) throws IOException {
|
private int readStringLength(boolean consume) throws IOException {
|
||||||
if(next == STRING_8) return readInt8(consume);
|
if (next == STRING_8) return readInt8(consume);
|
||||||
if(next == STRING_16) return readInt16(consume);
|
if (next == STRING_16) return readInt16(consume);
|
||||||
if(next == STRING_32) return readInt32(consume);
|
if (next == STRING_32) return readInt32(consume);
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void skipString() throws IOException {
|
public void skipString() throws IOException {
|
||||||
if(!hasString()) throw new FormatException();
|
if (!hasString()) throw new FormatException();
|
||||||
int length = readStringLength(false);
|
int length = readStringLength(false);
|
||||||
if(length < 0) throw new FormatException();
|
if (length < 0) throw new FormatException();
|
||||||
skip(length);
|
skip(length);
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasRaw() throws IOException {
|
public boolean hasRaw() throws IOException {
|
||||||
if(!hasLookahead) readLookahead();
|
if (!hasLookahead) readLookahead();
|
||||||
if(eof) return false;
|
if (eof) return false;
|
||||||
return next == RAW_8 || next == RAW_16 || next == RAW_32;
|
return next == RAW_8 || next == RAW_16 || next == RAW_32;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] readRaw(int maxLength) throws IOException {
|
public byte[] readRaw(int maxLength) throws IOException {
|
||||||
if(!hasRaw()) throw new FormatException();
|
if (!hasRaw()) throw new FormatException();
|
||||||
consumeLookahead();
|
consumeLookahead();
|
||||||
int length = readRawLength(true);
|
int length = readRawLength(true);
|
||||||
if(length < 0 || length > maxLength) throw new FormatException();
|
if (length < 0 || length > maxLength) throw new FormatException();
|
||||||
if(length == 0) return EMPTY_BUFFER;
|
if (length == 0) return EMPTY_BUFFER;
|
||||||
byte[] b = new byte[length];
|
byte[] b = new byte[length];
|
||||||
readIntoBuffer(b, length, true);
|
readIntoBuffer(b, length, true);
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int readRawLength(boolean consume) throws IOException {
|
private int readRawLength(boolean consume) throws IOException {
|
||||||
if(next == RAW_8) return readInt8(consume);
|
if (next == RAW_8) return readInt8(consume);
|
||||||
if(next == RAW_16) return readInt16(consume);
|
if (next == RAW_16) return readInt16(consume);
|
||||||
if(next == RAW_32) return readInt32(consume);
|
if (next == RAW_32) return readInt32(consume);
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void skipRaw() throws IOException {
|
public void skipRaw() throws IOException {
|
||||||
if(!hasRaw()) throw new FormatException();
|
if (!hasRaw()) throw new FormatException();
|
||||||
int length = readRawLength(false);
|
int length = readRawLength(false);
|
||||||
if(length < 0) throw new FormatException();
|
if (length < 0) throw new FormatException();
|
||||||
skip(length);
|
skip(length);
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasList() throws IOException {
|
public boolean hasList() throws IOException {
|
||||||
if(!hasLookahead) readLookahead();
|
if (!hasLookahead) readLookahead();
|
||||||
if(eof) return false;
|
if (eof) return false;
|
||||||
return next == LIST;
|
return next == LIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readListStart() throws IOException {
|
public void readListStart() throws IOException {
|
||||||
if(!hasList()) throw new FormatException();
|
if (!hasList()) throw new FormatException();
|
||||||
consumeLookahead();
|
consumeLookahead();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,8 +306,8 @@ class ReaderImpl implements Reader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasEnd() throws IOException {
|
private boolean hasEnd() throws IOException {
|
||||||
if(!hasLookahead) readLookahead();
|
if (!hasLookahead) readLookahead();
|
||||||
if(eof) return false;
|
if (eof) return false;
|
||||||
return next == END;
|
return next == END;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,25 +316,25 @@ class ReaderImpl implements Reader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void readEnd() throws IOException {
|
private void readEnd() throws IOException {
|
||||||
if(!hasEnd()) throw new FormatException();
|
if (!hasEnd()) throw new FormatException();
|
||||||
consumeLookahead();
|
consumeLookahead();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void skipList() throws IOException {
|
public void skipList() throws IOException {
|
||||||
if(!hasList()) throw new FormatException();
|
if (!hasList()) throw new FormatException();
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
while(!hasListEnd()) skipObject();
|
while (!hasListEnd()) skipObject();
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasMap() throws IOException {
|
public boolean hasMap() throws IOException {
|
||||||
if(!hasLookahead) readLookahead();
|
if (!hasLookahead) readLookahead();
|
||||||
if(eof) return false;
|
if (eof) return false;
|
||||||
return next == MAP;
|
return next == MAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readMapStart() throws IOException {
|
public void readMapStart() throws IOException {
|
||||||
if(!hasMap()) throw new FormatException();
|
if (!hasMap()) throw new FormatException();
|
||||||
consumeLookahead();
|
consumeLookahead();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,9 +347,9 @@ class ReaderImpl implements Reader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void skipMap() throws IOException {
|
public void skipMap() throws IOException {
|
||||||
if(!hasMap()) throw new FormatException();
|
if (!hasMap()) throw new FormatException();
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
while(!hasMapEnd()) {
|
while (!hasMapEnd()) {
|
||||||
skipObject();
|
skipObject();
|
||||||
skipObject();
|
skipObject();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class WriterImpl implements Writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void removeConsumer(Consumer c) {
|
public void removeConsumer(Consumer c) {
|
||||||
if(!consumers.remove(c)) throw new IllegalArgumentException();
|
if (!consumers.remove(c)) throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeNull() throws IOException {
|
public void writeNull() throws IOException {
|
||||||
@@ -61,18 +61,18 @@ class WriterImpl implements Writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void writeBoolean(boolean b) throws IOException {
|
public void writeBoolean(boolean b) throws IOException {
|
||||||
if(b) write(TRUE);
|
if (b) write(TRUE);
|
||||||
else write(FALSE);
|
else write(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeInteger(long i) throws IOException {
|
public void writeInteger(long i) throws IOException {
|
||||||
if(i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE) {
|
if (i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE) {
|
||||||
write(INT_8);
|
write(INT_8);
|
||||||
write((byte) i);
|
write((byte) i);
|
||||||
} else if(i >= Short.MIN_VALUE && i <= Short.MAX_VALUE) {
|
} else if (i >= Short.MIN_VALUE && i <= Short.MAX_VALUE) {
|
||||||
write(INT_16);
|
write(INT_16);
|
||||||
writeInt16((short) i);
|
writeInt16((short) i);
|
||||||
} else if(i >= Integer.MIN_VALUE && i <= Integer.MAX_VALUE) {
|
} else if (i >= Integer.MIN_VALUE && i <= Integer.MAX_VALUE) {
|
||||||
write(INT_32);
|
write(INT_32);
|
||||||
writeInt32((int) i);
|
writeInt32((int) i);
|
||||||
} else {
|
} else {
|
||||||
@@ -111,10 +111,10 @@ class WriterImpl implements Writer {
|
|||||||
|
|
||||||
public void writeString(String s) throws IOException {
|
public void writeString(String s) throws IOException {
|
||||||
byte[] b = s.getBytes("UTF-8");
|
byte[] b = s.getBytes("UTF-8");
|
||||||
if(b.length <= Byte.MAX_VALUE) {
|
if (b.length <= Byte.MAX_VALUE) {
|
||||||
write(STRING_8);
|
write(STRING_8);
|
||||||
write((byte) b.length);
|
write((byte) b.length);
|
||||||
} else if(b.length <= Short.MAX_VALUE) {
|
} else if (b.length <= Short.MAX_VALUE) {
|
||||||
write(STRING_16);
|
write(STRING_16);
|
||||||
writeInt16((short) b.length);
|
writeInt16((short) b.length);
|
||||||
} else {
|
} else {
|
||||||
@@ -125,10 +125,10 @@ class WriterImpl implements Writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void writeRaw(byte[] b) throws IOException {
|
public void writeRaw(byte[] b) throws IOException {
|
||||||
if(b.length <= Byte.MAX_VALUE) {
|
if (b.length <= Byte.MAX_VALUE) {
|
||||||
write(RAW_8);
|
write(RAW_8);
|
||||||
write((byte) b.length);
|
write((byte) b.length);
|
||||||
} else if(b.length <= Short.MAX_VALUE) {
|
} else if (b.length <= Short.MAX_VALUE) {
|
||||||
write(RAW_16);
|
write(RAW_16);
|
||||||
writeInt16((short) b.length);
|
writeInt16((short) b.length);
|
||||||
} else {
|
} else {
|
||||||
@@ -140,24 +140,24 @@ class WriterImpl implements Writer {
|
|||||||
|
|
||||||
public void writeList(Collection<?> c) throws IOException {
|
public void writeList(Collection<?> c) throws IOException {
|
||||||
write(LIST);
|
write(LIST);
|
||||||
for(Object o : c) writeObject(o);
|
for (Object o : c) writeObject(o);
|
||||||
write(END);
|
write(END);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeObject(Object o) throws IOException {
|
private void writeObject(Object o) throws IOException {
|
||||||
if(o instanceof Boolean) writeBoolean((Boolean) o);
|
if (o instanceof Boolean) writeBoolean((Boolean) o);
|
||||||
else if(o instanceof Byte) writeInteger((Byte) o);
|
else if (o instanceof Byte) writeInteger((Byte) o);
|
||||||
else if(o instanceof Short) writeInteger((Short) o);
|
else if (o instanceof Short) writeInteger((Short) o);
|
||||||
else if(o instanceof Integer) writeInteger((Integer) o);
|
else if (o instanceof Integer) writeInteger((Integer) o);
|
||||||
else if(o instanceof Long) writeInteger((Long) o);
|
else if (o instanceof Long) writeInteger((Long) o);
|
||||||
else if(o instanceof Float) writeFloat((Float) o);
|
else if (o instanceof Float) writeFloat((Float) o);
|
||||||
else if(o instanceof Double) writeFloat((Double) o);
|
else if (o instanceof Double) writeFloat((Double) o);
|
||||||
else if(o instanceof String) writeString((String) o);
|
else if (o instanceof String) writeString((String) o);
|
||||||
else if(o instanceof byte[]) writeRaw((byte[]) o);
|
else if (o instanceof byte[]) writeRaw((byte[]) o);
|
||||||
else if(o instanceof Bytes) writeRaw(((Bytes) o).getBytes());
|
else if (o instanceof Bytes) writeRaw(((Bytes) o).getBytes());
|
||||||
else if(o instanceof List<?>) writeList((List<?>) o);
|
else if (o instanceof List<?>) writeList((List<?>) o);
|
||||||
else if(o instanceof Map<?, ?>) writeMap((Map<?, ?>) o);
|
else if (o instanceof Map<?, ?>) writeMap((Map<?, ?>) o);
|
||||||
else if(o == null) writeNull();
|
else if (o == null) writeNull();
|
||||||
else throw new IllegalStateException();
|
else throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,7 +171,7 @@ class WriterImpl implements Writer {
|
|||||||
|
|
||||||
public void writeMap(Map<?, ?> m) throws IOException {
|
public void writeMap(Map<?, ?> m) throws IOException {
|
||||||
write(MAP);
|
write(MAP);
|
||||||
for(Entry<?, ?> e : m.entrySet()) {
|
for (Entry<?, ?> e : m.entrySet()) {
|
||||||
writeObject(e.getKey());
|
writeObject(e.getKey());
|
||||||
writeObject(e.getValue());
|
writeObject(e.getValue());
|
||||||
}
|
}
|
||||||
@@ -188,11 +188,11 @@ class WriterImpl implements Writer {
|
|||||||
|
|
||||||
private void write(byte b) throws IOException {
|
private void write(byte b) throws IOException {
|
||||||
out.write(b);
|
out.write(b);
|
||||||
for(Consumer c : consumers) c.write(b);
|
for (Consumer c : consumers) c.write(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void write(byte[] b) throws IOException {
|
private void write(byte[] b) throws IOException {
|
||||||
out.write(b);
|
out.write(b);
|
||||||
for(Consumer c : consumers) c.write(b, 0, b.length);
|
for (Consumer c : consumers) c.write(b, 0, b.length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,19 +35,19 @@ class DatabaseCleanerImpl extends TimerTask implements DatabaseCleaner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
if(callback == null) throw new IllegalStateException();
|
if (callback == null) throw new IllegalStateException();
|
||||||
try {
|
try {
|
||||||
if(callback.shouldCheckFreeSpace()) {
|
if (callback.shouldCheckFreeSpace()) {
|
||||||
LOG.info("Checking free space");
|
LOG.info("Checking free space");
|
||||||
callback.checkFreeSpaceAndClean();
|
callback.checkFreeSpaceAndClean();
|
||||||
}
|
}
|
||||||
} catch(DbClosedException e) {
|
} catch (DbClosedException e) {
|
||||||
LOG.info("Database closed, exiting");
|
LOG.info("Database closed, exiting");
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
throw new Error(e); // Kill the application
|
throw new Error(e); // Kill the application
|
||||||
} catch(RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
throw new Error(e); // Kill the application
|
throw new Error(e); // Kill the application
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -12,15 +12,15 @@ class ExponentialBackoff {
|
|||||||
* be greater than Long.MAX_VALUE, Long.MAX_VALUE is returned.
|
* be greater than Long.MAX_VALUE, Long.MAX_VALUE is returned.
|
||||||
*/
|
*/
|
||||||
static long calculateExpiry(long now, int maxLatency, int txCount) {
|
static long calculateExpiry(long now, int maxLatency, int txCount) {
|
||||||
if(now < 0) throw new IllegalArgumentException();
|
if (now < 0) throw new IllegalArgumentException();
|
||||||
if(maxLatency <= 0) throw new IllegalArgumentException();
|
if (maxLatency <= 0) throw new IllegalArgumentException();
|
||||||
if(txCount < 0) throw new IllegalArgumentException();
|
if (txCount < 0) throw new IllegalArgumentException();
|
||||||
// The maximum round-trip time is twice the maximum latency
|
// The maximum round-trip time is twice the maximum latency
|
||||||
long roundTrip = maxLatency * 2L;
|
long roundTrip = maxLatency * 2L;
|
||||||
// The interval between transmissions is roundTrip * 2 ^ txCount
|
// The interval between transmissions is roundTrip * 2 ^ txCount
|
||||||
for(int i = 0; i < txCount; i++) {
|
for (int i = 0; i < txCount; i++) {
|
||||||
roundTrip <<= 1;
|
roundTrip <<= 1;
|
||||||
if(roundTrip < 0) return Long.MAX_VALUE;
|
if (roundTrip < 0) return Long.MAX_VALUE;
|
||||||
}
|
}
|
||||||
// The expiry time is the current time plus the interval
|
// The expiry time is the current time plus the interval
|
||||||
long expiry = now + roundTrip;
|
long expiry = now + roundTrip;
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class H2Database extends JdbcDatabase {
|
|||||||
|
|
||||||
public boolean open() throws DbException, IOException {
|
public boolean open() throws DbException, IOException {
|
||||||
boolean reopen = config.databaseExists();
|
boolean reopen = config.databaseExists();
|
||||||
if(!reopen) config.getDatabaseDirectory().mkdirs();
|
if (!reopen) config.getDatabaseDirectory().mkdirs();
|
||||||
super.open("org.h2.Driver", reopen);
|
super.open("org.h2.Driver", reopen);
|
||||||
return reopen;
|
return reopen;
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,7 @@ class H2Database extends JdbcDatabase {
|
|||||||
// H2 will close the database when the last connection closes
|
// H2 will close the database when the last connection closes
|
||||||
try {
|
try {
|
||||||
super.closeAllConnections();
|
super.closeAllConnections();
|
||||||
} catch(SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new DbException(e);
|
throw new DbException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,17 +64,17 @@ class H2Database extends JdbcDatabase {
|
|||||||
long quota = maxSize - used;
|
long quota = maxSize - used;
|
||||||
long min = Math.min(free, quota);
|
long min = Math.min(free, quota);
|
||||||
return min;
|
return min;
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
throw new DbException(e);
|
throw new DbException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private long getDiskSpace(File f) {
|
private long getDiskSpace(File f) {
|
||||||
if(f.isDirectory()) {
|
if (f.isDirectory()) {
|
||||||
long total = 0;
|
long total = 0;
|
||||||
for(File child : f.listFiles()) total += getDiskSpace(child);
|
for (File child : f.listFiles()) total += getDiskSpace(child);
|
||||||
return total;
|
return total;
|
||||||
} else if(f.isFile()) {
|
} else if (f.isFile()) {
|
||||||
return f.length();
|
return f.length();
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -84,7 +84,7 @@ class H2Database extends JdbcDatabase {
|
|||||||
@Override
|
@Override
|
||||||
protected Connection createConnection() throws SQLException {
|
protected Connection createConnection() throws SQLException {
|
||||||
byte[] key = config.getEncryptionKey().getBytes();
|
byte[] key = config.getEncryptionKey().getBytes();
|
||||||
if(key == null) throw new IllegalStateException();
|
if (key == null) throw new IllegalStateException();
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
props.setProperty("user", "user");
|
props.setProperty("user", "user");
|
||||||
// Separate the file password from the user password with a space
|
// Separate the file password from the user password with a space
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -21,6 +21,6 @@ class EventBusImpl implements EventBus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void broadcast(Event e) {
|
public void broadcast(Event e) {
|
||||||
for(EventListener l : listeners) l.eventOccurred(e);
|
for (EventListener l : listeners) l.eventOccurred(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,11 +58,11 @@ class AliceConnector extends Connector {
|
|||||||
public void run() {
|
public void run() {
|
||||||
// Create an incoming or outgoing connection
|
// Create an incoming or outgoing connection
|
||||||
DuplexTransportConnection conn = createInvitationConnection();
|
DuplexTransportConnection conn = createInvitationConnection();
|
||||||
if(conn == null) return;
|
if (conn == null) return;
|
||||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " connected");
|
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " connected");
|
||||||
// Don't proceed with more than one connection
|
// Don't proceed with more than one connection
|
||||||
if(group.getAndSetConnected()) {
|
if (group.getAndSetConnected()) {
|
||||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " redundant");
|
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " redundant");
|
||||||
tryToClose(conn, false);
|
tryToClose(conn, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -83,19 +83,19 @@ class AliceConnector extends Connector {
|
|||||||
sendPublicKey(w);
|
sendPublicKey(w);
|
||||||
byte[] key = receivePublicKey(r);
|
byte[] key = receivePublicKey(r);
|
||||||
secret = deriveMasterSecret(hash, key, true);
|
secret = deriveMasterSecret(hash, key, true);
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
group.keyAgreementFailed();
|
group.keyAgreementFailed();
|
||||||
tryToClose(conn, true);
|
tryToClose(conn, true);
|
||||||
return;
|
return;
|
||||||
} catch(GeneralSecurityException e) {
|
} catch (GeneralSecurityException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
group.keyAgreementFailed();
|
group.keyAgreementFailed();
|
||||||
tryToClose(conn, true);
|
tryToClose(conn, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// The key agreement succeeded - derive the confirmation codes
|
// The key agreement succeeded - derive the confirmation codes
|
||||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " agreement succeeded");
|
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " agreement succeeded");
|
||||||
int[] codes = crypto.deriveConfirmationCodes(secret);
|
int[] codes = crypto.deriveConfirmationCodes(secret);
|
||||||
int aliceCode = codes[0], bobCode = codes[1];
|
int aliceCode = codes[0], bobCode = codes[1];
|
||||||
group.keyAgreementSucceeded(aliceCode, bobCode);
|
group.keyAgreementSucceeded(aliceCode, bobCode);
|
||||||
@@ -105,22 +105,22 @@ class AliceConnector extends Connector {
|
|||||||
localMatched = group.waitForLocalConfirmationResult();
|
localMatched = group.waitForLocalConfirmationResult();
|
||||||
sendConfirmation(w, localMatched);
|
sendConfirmation(w, localMatched);
|
||||||
remoteMatched = receiveConfirmation(r);
|
remoteMatched = receiveConfirmation(r);
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
group.remoteConfirmationFailed();
|
group.remoteConfirmationFailed();
|
||||||
tryToClose(conn, true);
|
tryToClose(conn, true);
|
||||||
return;
|
return;
|
||||||
} catch(InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.warning("Interrupted while waiting for confirmation");
|
LOG.warning("Interrupted while waiting for confirmation");
|
||||||
group.remoteConfirmationFailed();
|
group.remoteConfirmationFailed();
|
||||||
tryToClose(conn, true);
|
tryToClose(conn, true);
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(remoteMatched) group.remoteConfirmationSucceeded();
|
if (remoteMatched) group.remoteConfirmationSucceeded();
|
||||||
else group.remoteConfirmationFailed();
|
else group.remoteConfirmationFailed();
|
||||||
if(!(localMatched && remoteMatched)) {
|
if (!(localMatched && remoteMatched)) {
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info(pluginName + " confirmation failed");
|
LOG.info(pluginName + " confirmation failed");
|
||||||
tryToClose(conn, false);
|
tryToClose(conn, false);
|
||||||
return;
|
return;
|
||||||
@@ -128,7 +128,7 @@ class AliceConnector extends Connector {
|
|||||||
// The timestamp is taken after exchanging confirmation results
|
// The timestamp is taken after exchanging confirmation results
|
||||||
long localTimestamp = clock.currentTimeMillis();
|
long localTimestamp = clock.currentTimeMillis();
|
||||||
// Confirmation succeeded - upgrade to a secure connection
|
// Confirmation succeeded - upgrade to a secure connection
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info(pluginName + " confirmation succeeded");
|
LOG.info(pluginName + " confirmation succeeded");
|
||||||
// Create the readers
|
// Create the readers
|
||||||
InputStream streamReader =
|
InputStream streamReader =
|
||||||
@@ -159,14 +159,14 @@ class AliceConnector extends Connector {
|
|||||||
remoteReuseConnection = receiveConfirmation(r);
|
remoteReuseConnection = receiveConfirmation(r);
|
||||||
// Close the outgoing stream and expect EOF on the incoming stream
|
// Close the outgoing stream and expect EOF on the incoming stream
|
||||||
w.close();
|
w.close();
|
||||||
if(!r.eof()) LOG.warning("Unexpected data at end of connection");
|
if (!r.eof()) LOG.warning("Unexpected data at end of connection");
|
||||||
} catch(GeneralSecurityException e) {
|
} catch (GeneralSecurityException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
group.pseudonymExchangeFailed();
|
group.pseudonymExchangeFailed();
|
||||||
tryToClose(conn, true);
|
tryToClose(conn, true);
|
||||||
return;
|
return;
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
group.pseudonymExchangeFailed();
|
group.pseudonymExchangeFailed();
|
||||||
tryToClose(conn, true);
|
tryToClose(conn, true);
|
||||||
return;
|
return;
|
||||||
@@ -176,17 +176,17 @@ class AliceConnector extends Connector {
|
|||||||
// Add the contact and store the transports
|
// Add the contact and store the transports
|
||||||
try {
|
try {
|
||||||
addContact(remoteAuthor, remoteProps, secret, epoch, true);
|
addContact(remoteAuthor, remoteProps, secret, epoch, true);
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
tryToClose(conn, true);
|
tryToClose(conn, true);
|
||||||
group.pseudonymExchangeFailed();
|
group.pseudonymExchangeFailed();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Reuse the connection as a transport connection if both peers agree
|
// Reuse the connection as a transport connection if both peers agree
|
||||||
if(reuseConnection && remoteReuseConnection) reuseConnection(conn);
|
if (reuseConnection && remoteReuseConnection) reuseConnection(conn);
|
||||||
else tryToClose(conn, false);
|
else tryToClose(conn, false);
|
||||||
// Pseudonym exchange succeeded
|
// Pseudonym exchange succeeded
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info(pluginName + " pseudonym exchange succeeded");
|
LOG.info(pluginName + " pseudonym exchange succeeded");
|
||||||
group.pseudonymExchangeSucceeded(remoteAuthor);
|
group.pseudonymExchangeSucceeded(remoteAuthor);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,8 +58,8 @@ class BobConnector extends Connector {
|
|||||||
public void run() {
|
public void run() {
|
||||||
// Create an incoming or outgoing connection
|
// Create an incoming or outgoing connection
|
||||||
DuplexTransportConnection conn = createInvitationConnection();
|
DuplexTransportConnection conn = createInvitationConnection();
|
||||||
if(conn == null) return;
|
if (conn == null) return;
|
||||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " connected");
|
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " connected");
|
||||||
// Carry out the key agreement protocol
|
// Carry out the key agreement protocol
|
||||||
InputStream in;
|
InputStream in;
|
||||||
OutputStream out;
|
OutputStream out;
|
||||||
@@ -74,8 +74,8 @@ class BobConnector extends Connector {
|
|||||||
// Alice goes first
|
// Alice goes first
|
||||||
byte[] hash = receivePublicKeyHash(r);
|
byte[] hash = receivePublicKeyHash(r);
|
||||||
// Don't proceed with more than one connection
|
// Don't proceed with more than one connection
|
||||||
if(group.getAndSetConnected()) {
|
if (group.getAndSetConnected()) {
|
||||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " redundant");
|
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " redundant");
|
||||||
tryToClose(conn, false);
|
tryToClose(conn, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -83,19 +83,19 @@ class BobConnector extends Connector {
|
|||||||
byte[] key = receivePublicKey(r);
|
byte[] key = receivePublicKey(r);
|
||||||
sendPublicKey(w);
|
sendPublicKey(w);
|
||||||
secret = deriveMasterSecret(hash, key, false);
|
secret = deriveMasterSecret(hash, key, false);
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
group.keyAgreementFailed();
|
group.keyAgreementFailed();
|
||||||
tryToClose(conn, true);
|
tryToClose(conn, true);
|
||||||
return;
|
return;
|
||||||
} catch(GeneralSecurityException e) {
|
} catch (GeneralSecurityException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
group.keyAgreementFailed();
|
group.keyAgreementFailed();
|
||||||
tryToClose(conn, true);
|
tryToClose(conn, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// The key agreement succeeded - derive the confirmation codes
|
// The key agreement succeeded - derive the confirmation codes
|
||||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " agreement succeeded");
|
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " agreement succeeded");
|
||||||
int[] codes = crypto.deriveConfirmationCodes(secret);
|
int[] codes = crypto.deriveConfirmationCodes(secret);
|
||||||
int aliceCode = codes[0], bobCode = codes[1];
|
int aliceCode = codes[0], bobCode = codes[1];
|
||||||
group.keyAgreementSucceeded(bobCode, aliceCode);
|
group.keyAgreementSucceeded(bobCode, aliceCode);
|
||||||
@@ -105,22 +105,22 @@ class BobConnector extends Connector {
|
|||||||
remoteMatched = receiveConfirmation(r);
|
remoteMatched = receiveConfirmation(r);
|
||||||
localMatched = group.waitForLocalConfirmationResult();
|
localMatched = group.waitForLocalConfirmationResult();
|
||||||
sendConfirmation(w, localMatched);
|
sendConfirmation(w, localMatched);
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
group.remoteConfirmationFailed();
|
group.remoteConfirmationFailed();
|
||||||
tryToClose(conn, true);
|
tryToClose(conn, true);
|
||||||
return;
|
return;
|
||||||
} catch(InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.warning("Interrupted while waiting for confirmation");
|
LOG.warning("Interrupted while waiting for confirmation");
|
||||||
group.remoteConfirmationFailed();
|
group.remoteConfirmationFailed();
|
||||||
tryToClose(conn, true);
|
tryToClose(conn, true);
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(remoteMatched) group.remoteConfirmationSucceeded();
|
if (remoteMatched) group.remoteConfirmationSucceeded();
|
||||||
else group.remoteConfirmationFailed();
|
else group.remoteConfirmationFailed();
|
||||||
if(!(localMatched && remoteMatched)) {
|
if (!(localMatched && remoteMatched)) {
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info(pluginName + " confirmation failed");
|
LOG.info(pluginName + " confirmation failed");
|
||||||
tryToClose(conn, false);
|
tryToClose(conn, false);
|
||||||
return;
|
return;
|
||||||
@@ -128,7 +128,7 @@ class BobConnector extends Connector {
|
|||||||
// The timestamp is taken after exchanging confirmation results
|
// The timestamp is taken after exchanging confirmation results
|
||||||
long localTimestamp = clock.currentTimeMillis();
|
long localTimestamp = clock.currentTimeMillis();
|
||||||
// Confirmation succeeded - upgrade to a secure connection
|
// Confirmation succeeded - upgrade to a secure connection
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info(pluginName + " confirmation succeeded");
|
LOG.info(pluginName + " confirmation succeeded");
|
||||||
// Create the readers
|
// Create the readers
|
||||||
InputStream streamReader =
|
InputStream streamReader =
|
||||||
@@ -159,14 +159,14 @@ class BobConnector extends Connector {
|
|||||||
sendConfirmation(w, reuseConnection);
|
sendConfirmation(w, reuseConnection);
|
||||||
// Close the outgoing stream and expect EOF on the incoming stream
|
// Close the outgoing stream and expect EOF on the incoming stream
|
||||||
w.close();
|
w.close();
|
||||||
if(!r.eof()) LOG.warning("Unexpected data at end of connection");
|
if (!r.eof()) LOG.warning("Unexpected data at end of connection");
|
||||||
} catch(GeneralSecurityException e) {
|
} catch (GeneralSecurityException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
group.pseudonymExchangeFailed();
|
group.pseudonymExchangeFailed();
|
||||||
tryToClose(conn, true);
|
tryToClose(conn, true);
|
||||||
return;
|
return;
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
group.pseudonymExchangeFailed();
|
group.pseudonymExchangeFailed();
|
||||||
tryToClose(conn, true);
|
tryToClose(conn, true);
|
||||||
return;
|
return;
|
||||||
@@ -176,17 +176,17 @@ class BobConnector extends Connector {
|
|||||||
// Add the contact and store the transports
|
// Add the contact and store the transports
|
||||||
try {
|
try {
|
||||||
addContact(remoteAuthor, remoteProps, secret, epoch, false);
|
addContact(remoteAuthor, remoteProps, secret, epoch, false);
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
tryToClose(conn, true);
|
tryToClose(conn, true);
|
||||||
group.pseudonymExchangeFailed();
|
group.pseudonymExchangeFailed();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Reuse the connection as a transport connection if both peers agree
|
// Reuse the connection as a transport connection if both peers agree
|
||||||
if(reuseConnection && remoteReuseConnection) reuseConnection(conn);
|
if (reuseConnection && remoteReuseConnection) reuseConnection(conn);
|
||||||
else tryToClose(conn, false);
|
else tryToClose(conn, false);
|
||||||
// Pseudonym exchange succeeded
|
// Pseudonym exchange succeeded
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info(pluginName + " pseudonym exchange succeeded");
|
LOG.info(pluginName + " pseudonym exchange succeeded");
|
||||||
group.pseudonymExchangeSucceeded(remoteAuthor);
|
group.pseudonymExchangeSucceeded(remoteAuthor);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ abstract class Connector extends Thread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected DuplexTransportConnection createInvitationConnection() {
|
protected DuplexTransportConnection createInvitationConnection() {
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info(pluginName + " creating invitation connection");
|
LOG.info(pluginName + " creating invitation connection");
|
||||||
return plugin.createInvitationConnection(random, CONNECTION_TIMEOUT);
|
return plugin.createInvitationConnection(random, CONNECTION_TIMEOUT);
|
||||||
}
|
}
|
||||||
@@ -126,14 +126,14 @@ abstract class Connector extends Thread {
|
|||||||
protected void sendPublicKeyHash(Writer w) throws IOException {
|
protected void sendPublicKeyHash(Writer w) throws IOException {
|
||||||
w.writeRaw(messageDigest.digest(keyPair.getPublic().getEncoded()));
|
w.writeRaw(messageDigest.digest(keyPair.getPublic().getEncoded()));
|
||||||
w.flush();
|
w.flush();
|
||||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " sent hash");
|
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " sent hash");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected byte[] receivePublicKeyHash(Reader r) throws IOException {
|
protected byte[] receivePublicKeyHash(Reader r) throws IOException {
|
||||||
int hashLength = messageDigest.getDigestLength();
|
int hashLength = messageDigest.getDigestLength();
|
||||||
byte[] b = r.readRaw(hashLength);
|
byte[] b = r.readRaw(hashLength);
|
||||||
if(b.length < hashLength) throw new FormatException();
|
if (b.length < hashLength) throw new FormatException();
|
||||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " received hash");
|
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " received hash");
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,27 +141,27 @@ abstract class Connector extends Thread {
|
|||||||
byte[] key = keyPair.getPublic().getEncoded();
|
byte[] key = keyPair.getPublic().getEncoded();
|
||||||
w.writeRaw(key);
|
w.writeRaw(key);
|
||||||
w.flush();
|
w.flush();
|
||||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " sent key");
|
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " sent key");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected byte[] receivePublicKey(Reader r) throws GeneralSecurityException,
|
protected byte[] receivePublicKey(Reader r) throws GeneralSecurityException,
|
||||||
IOException {
|
IOException {
|
||||||
byte[] b = r.readRaw(MAX_PUBLIC_KEY_LENGTH);
|
byte[] b = r.readRaw(MAX_PUBLIC_KEY_LENGTH);
|
||||||
keyParser.parsePublicKey(b);
|
keyParser.parsePublicKey(b);
|
||||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " received key");
|
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " received key");
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected byte[] deriveMasterSecret(byte[] hash, byte[] key, boolean alice)
|
protected byte[] deriveMasterSecret(byte[] hash, byte[] key, boolean alice)
|
||||||
throws GeneralSecurityException {
|
throws GeneralSecurityException {
|
||||||
// Check that the hash matches the key
|
// Check that the hash matches the key
|
||||||
if(!Arrays.equals(hash, messageDigest.digest(key))) {
|
if (!Arrays.equals(hash, messageDigest.digest(key))) {
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info(pluginName + " hash does not match key");
|
LOG.info(pluginName + " hash does not match key");
|
||||||
throw new GeneralSecurityException();
|
throw new GeneralSecurityException();
|
||||||
}
|
}
|
||||||
// Derive the master secret
|
// Derive the master secret
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info(pluginName + " deriving master secret");
|
LOG.info(pluginName + " deriving master secret");
|
||||||
return crypto.deriveMasterSecret(key, keyPair, alice);
|
return crypto.deriveMasterSecret(key, keyPair, alice);
|
||||||
}
|
}
|
||||||
@@ -170,13 +170,13 @@ abstract class Connector extends Thread {
|
|||||||
throws IOException {
|
throws IOException {
|
||||||
w.writeBoolean(confirmed);
|
w.writeBoolean(confirmed);
|
||||||
w.flush();
|
w.flush();
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info(pluginName + " sent confirmation: " + confirmed);
|
LOG.info(pluginName + " sent confirmation: " + confirmed);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean receiveConfirmation(Reader r) throws IOException {
|
protected boolean receiveConfirmation(Reader r) throws IOException {
|
||||||
boolean confirmed = r.readBoolean();
|
boolean confirmed = r.readBoolean();
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info(pluginName + " received confirmation: " + confirmed);
|
LOG.info(pluginName + " received confirmation: " + confirmed);
|
||||||
return confirmed;
|
return confirmed;
|
||||||
}
|
}
|
||||||
@@ -195,7 +195,7 @@ abstract class Connector extends Thread {
|
|||||||
w.writeRaw(localAuthor.getPublicKey());
|
w.writeRaw(localAuthor.getPublicKey());
|
||||||
w.writeRaw(sig);
|
w.writeRaw(sig);
|
||||||
w.flush();
|
w.flush();
|
||||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " sent pseudonym");
|
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " sent pseudonym");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Author receivePseudonym(Reader r, byte[] nonce)
|
protected Author receivePseudonym(Reader r, byte[] nonce)
|
||||||
@@ -204,14 +204,14 @@ abstract class Connector extends Thread {
|
|||||||
String name = r.readString(MAX_AUTHOR_NAME_LENGTH);
|
String name = r.readString(MAX_AUTHOR_NAME_LENGTH);
|
||||||
byte[] publicKey = r.readRaw(MAX_PUBLIC_KEY_LENGTH);
|
byte[] publicKey = r.readRaw(MAX_PUBLIC_KEY_LENGTH);
|
||||||
byte[] sig = r.readRaw(MAX_SIGNATURE_LENGTH);
|
byte[] sig = r.readRaw(MAX_SIGNATURE_LENGTH);
|
||||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " received pseudonym");
|
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " received pseudonym");
|
||||||
// Verify the signature
|
// Verify the signature
|
||||||
Signature signature = crypto.getSignature();
|
Signature signature = crypto.getSignature();
|
||||||
KeyParser keyParser = crypto.getSignatureKeyParser();
|
KeyParser keyParser = crypto.getSignatureKeyParser();
|
||||||
signature.initVerify(keyParser.parsePublicKey(publicKey));
|
signature.initVerify(keyParser.parsePublicKey(publicKey));
|
||||||
signature.update(nonce);
|
signature.update(nonce);
|
||||||
if(!signature.verify(sig)) {
|
if (!signature.verify(sig)) {
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info(pluginName + " invalid signature");
|
LOG.info(pluginName + " invalid signature");
|
||||||
throw new GeneralSecurityException();
|
throw new GeneralSecurityException();
|
||||||
}
|
}
|
||||||
@@ -221,25 +221,25 @@ abstract class Connector extends Thread {
|
|||||||
protected void sendTimestamp(Writer w, long timestamp) throws IOException {
|
protected void sendTimestamp(Writer w, long timestamp) throws IOException {
|
||||||
w.writeInteger(timestamp);
|
w.writeInteger(timestamp);
|
||||||
w.flush();
|
w.flush();
|
||||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " sent timestamp");
|
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " sent timestamp");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected long receiveTimestamp(Reader r) throws IOException {
|
protected long receiveTimestamp(Reader r) throws IOException {
|
||||||
long timestamp = r.readInteger();
|
long timestamp = r.readInteger();
|
||||||
if(timestamp < 0) throw new FormatException();
|
if (timestamp < 0) throw new FormatException();
|
||||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " received timestamp");
|
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " received timestamp");
|
||||||
return timestamp;
|
return timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void sendTransportProperties(Writer w) throws IOException {
|
protected void sendTransportProperties(Writer w) throws IOException {
|
||||||
w.writeListStart();
|
w.writeListStart();
|
||||||
for(Entry<TransportId, TransportProperties> e : localProps.entrySet()) {
|
for (Entry<TransportId, TransportProperties> e : localProps.entrySet()) {
|
||||||
w.writeString(e.getKey().getString());
|
w.writeString(e.getKey().getString());
|
||||||
w.writeMap(e.getValue());
|
w.writeMap(e.getValue());
|
||||||
}
|
}
|
||||||
w.writeListEnd();
|
w.writeListEnd();
|
||||||
w.flush();
|
w.flush();
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info(pluginName + " sent transport properties");
|
LOG.info(pluginName + " sent transport properties");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,14 +248,14 @@ abstract class Connector extends Thread {
|
|||||||
Map<TransportId, TransportProperties> remoteProps =
|
Map<TransportId, TransportProperties> remoteProps =
|
||||||
new HashMap<TransportId, TransportProperties>();
|
new HashMap<TransportId, TransportProperties>();
|
||||||
r.readListStart();
|
r.readListStart();
|
||||||
while(!r.hasListEnd()) {
|
while (!r.hasListEnd()) {
|
||||||
String idString = r.readString(MAX_TRANSPORT_ID_LENGTH);
|
String idString = r.readString(MAX_TRANSPORT_ID_LENGTH);
|
||||||
if(idString.length() == 0) throw new FormatException();
|
if (idString.length() == 0) throw new FormatException();
|
||||||
TransportId id = new TransportId(idString);
|
TransportId id = new TransportId(idString);
|
||||||
Map<String, String> p = new HashMap<String, String>();
|
Map<String, String> p = new HashMap<String, String>();
|
||||||
r.readMapStart();
|
r.readMapStart();
|
||||||
for(int i = 0; !r.hasMapEnd(); i++) {
|
for (int i = 0; !r.hasMapEnd(); i++) {
|
||||||
if(i == MAX_PROPERTIES_PER_TRANSPORT)
|
if (i == MAX_PROPERTIES_PER_TRANSPORT)
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
String key = r.readString(MAX_PROPERTY_LENGTH);
|
String key = r.readString(MAX_PROPERTY_LENGTH);
|
||||||
String value = r.readString(MAX_PROPERTY_LENGTH);
|
String value = r.readString(MAX_PROPERTY_LENGTH);
|
||||||
@@ -265,7 +265,7 @@ abstract class Connector extends Thread {
|
|||||||
remoteProps.put(id, new TransportProperties(p));
|
remoteProps.put(id, new TransportProperties(p));
|
||||||
}
|
}
|
||||||
r.readListEnd();
|
r.readListEnd();
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info(pluginName + " received transport properties");
|
LOG.info(pluginName + " received transport properties");
|
||||||
return remoteProps;
|
return remoteProps;
|
||||||
}
|
}
|
||||||
@@ -285,20 +285,20 @@ abstract class Connector extends Thread {
|
|||||||
// Create an endpoint for each transport shared with the contact
|
// Create an endpoint for each transport shared with the contact
|
||||||
List<TransportId> ids = new ArrayList<TransportId>();
|
List<TransportId> ids = new ArrayList<TransportId>();
|
||||||
Map<TransportId, Integer> latencies = db.getTransportLatencies();
|
Map<TransportId, Integer> latencies = db.getTransportLatencies();
|
||||||
for(TransportId id : localProps.keySet()) {
|
for (TransportId id : localProps.keySet()) {
|
||||||
if(latencies.containsKey(id) && remoteProps.containsKey(id))
|
if (latencies.containsKey(id) && remoteProps.containsKey(id))
|
||||||
ids.add(id);
|
ids.add(id);
|
||||||
}
|
}
|
||||||
// Assign indices to the transports deterministically and derive keys
|
// Assign indices to the transports deterministically and derive keys
|
||||||
Collections.sort(ids, TransportIdComparator.INSTANCE);
|
Collections.sort(ids, TransportIdComparator.INSTANCE);
|
||||||
int size = ids.size();
|
int size = ids.size();
|
||||||
for(int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
TransportId id = ids.get(i);
|
TransportId id = ids.get(i);
|
||||||
Endpoint ep = new Endpoint(contactId, id, epoch, alice);
|
Endpoint ep = new Endpoint(contactId, id, epoch, alice);
|
||||||
int maxLatency = latencies.get(id);
|
int maxLatency = latencies.get(id);
|
||||||
try {
|
try {
|
||||||
db.addEndpoint(ep);
|
db.addEndpoint(ep);
|
||||||
} catch(NoSuchTransportException e) {
|
} catch (NoSuchTransportException e) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
byte[] initialSecret = crypto.deriveInitialSecret(secret, i);
|
byte[] initialSecret = crypto.deriveInitialSecret(secret, i);
|
||||||
@@ -312,13 +312,13 @@ abstract class Connector extends Thread {
|
|||||||
LOG.info("Closing connection");
|
LOG.info("Closing connection");
|
||||||
conn.getReader().dispose(exception, true);
|
conn.getReader().dispose(exception, true);
|
||||||
conn.getWriter().dispose(exception);
|
conn.getWriter().dispose(exception);
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void reuseConnection(DuplexTransportConnection conn) {
|
protected void reuseConnection(DuplexTransportConnection conn) {
|
||||||
if(contactId == null) throw new IllegalStateException();
|
if (contactId == null) throw new IllegalStateException();
|
||||||
TransportId t = plugin.getId();
|
TransportId t = plugin.getId();
|
||||||
connectionManager.manageOutgoingConnection(contactId, t, conn);
|
connectionManager.manageOutgoingConnection(contactId, t, conn);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,29 +132,29 @@ class ConnectorGroup extends Thread implements InvitationTask {
|
|||||||
try {
|
try {
|
||||||
localAuthor = db.getLocalAuthor(localAuthorId);
|
localAuthor = db.getLocalAuthor(localAuthorId);
|
||||||
localProps = db.getLocalProperties();
|
localProps = db.getLocalProperties();
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
synchLock.lock();
|
synchLock.lock();
|
||||||
try {
|
try {
|
||||||
connectionFailed = true;
|
connectionFailed = true;
|
||||||
} finally {
|
} finally {
|
||||||
synchLock.unlock();
|
synchLock.unlock();
|
||||||
}
|
}
|
||||||
for(InvitationListener l : listeners) l.connectionFailed();
|
for (InvitationListener l : listeners) l.connectionFailed();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Start the connection threads
|
// Start the connection threads
|
||||||
Collection<Connector> connectors = new ArrayList<Connector>();
|
Collection<Connector> connectors = new ArrayList<Connector>();
|
||||||
// Alice is the party with the smaller invitation code
|
// Alice is the party with the smaller invitation code
|
||||||
if(localInvitationCode < remoteInvitationCode) {
|
if (localInvitationCode < remoteInvitationCode) {
|
||||||
for(DuplexPlugin plugin : pluginManager.getInvitationPlugins()) {
|
for (DuplexPlugin plugin : pluginManager.getInvitationPlugins()) {
|
||||||
Connector c = createAliceConnector(plugin, localAuthor,
|
Connector c = createAliceConnector(plugin, localAuthor,
|
||||||
localProps);
|
localProps);
|
||||||
connectors.add(c);
|
connectors.add(c);
|
||||||
c.start();
|
c.start();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for(DuplexPlugin plugin: pluginManager.getInvitationPlugins()) {
|
for (DuplexPlugin plugin: pluginManager.getInvitationPlugins()) {
|
||||||
Connector c = createBobConnector(plugin, localAuthor,
|
Connector c = createBobConnector(plugin, localAuthor,
|
||||||
localProps);
|
localProps);
|
||||||
connectors.add(c);
|
connectors.add(c);
|
||||||
@@ -163,20 +163,20 @@ class ConnectorGroup extends Thread implements InvitationTask {
|
|||||||
}
|
}
|
||||||
// Wait for the connection threads to finish
|
// Wait for the connection threads to finish
|
||||||
try {
|
try {
|
||||||
for(Connector c : connectors) c.join();
|
for (Connector c : connectors) c.join();
|
||||||
} catch(InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.warning("Interrupted while waiting for connectors");
|
LOG.warning("Interrupted while waiting for connectors");
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
// If none of the threads connected, inform the listeners
|
// If none of the threads connected, inform the listeners
|
||||||
if(!connected.get()) {
|
if (!connected.get()) {
|
||||||
synchLock.lock();
|
synchLock.lock();
|
||||||
try {
|
try {
|
||||||
connectionFailed = true;
|
connectionFailed = true;
|
||||||
} finally {
|
} finally {
|
||||||
synchLock.unlock();
|
synchLock.unlock();
|
||||||
}
|
}
|
||||||
for(InvitationListener l : listeners) l.connectionFailed();
|
for (InvitationListener l : listeners) l.connectionFailed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,8 +226,8 @@ class ConnectorGroup extends Thread implements InvitationTask {
|
|||||||
|
|
||||||
boolean getAndSetConnected() {
|
boolean getAndSetConnected() {
|
||||||
boolean redundant = connected.getAndSet(true);
|
boolean redundant = connected.getAndSet(true);
|
||||||
if(!redundant)
|
if (!redundant)
|
||||||
for(InvitationListener l : listeners) l.connectionSucceeded();
|
for (InvitationListener l : listeners) l.connectionSucceeded();
|
||||||
return redundant;
|
return redundant;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,12 +239,12 @@ class ConnectorGroup extends Thread implements InvitationTask {
|
|||||||
} finally {
|
} finally {
|
||||||
synchLock.unlock();
|
synchLock.unlock();
|
||||||
}
|
}
|
||||||
for(InvitationListener l : listeners)
|
for (InvitationListener l : listeners)
|
||||||
l.keyAgreementSucceeded(localCode, remoteCode);
|
l.keyAgreementSucceeded(localCode, remoteCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void keyAgreementFailed() {
|
void keyAgreementFailed() {
|
||||||
for(InvitationListener l : listeners) l.keyAgreementFailed();
|
for (InvitationListener l : listeners) l.keyAgreementFailed();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean waitForLocalConfirmationResult() throws InterruptedException {
|
boolean waitForLocalConfirmationResult() throws InterruptedException {
|
||||||
@@ -265,7 +265,7 @@ class ConnectorGroup extends Thread implements InvitationTask {
|
|||||||
} finally {
|
} finally {
|
||||||
synchLock.unlock();
|
synchLock.unlock();
|
||||||
}
|
}
|
||||||
for(InvitationListener l : listeners) l.remoteConfirmationSucceeded();
|
for (InvitationListener l : listeners) l.remoteConfirmationSucceeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void remoteConfirmationFailed() {
|
void remoteConfirmationFailed() {
|
||||||
@@ -276,7 +276,7 @@ class ConnectorGroup extends Thread implements InvitationTask {
|
|||||||
} finally {
|
} finally {
|
||||||
synchLock.unlock();
|
synchLock.unlock();
|
||||||
}
|
}
|
||||||
for(InvitationListener l : listeners) l.remoteConfirmationFailed();
|
for (InvitationListener l : listeners) l.remoteConfirmationFailed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pseudonymExchangeSucceeded(Author remoteAuthor) {
|
void pseudonymExchangeSucceeded(Author remoteAuthor) {
|
||||||
@@ -287,11 +287,11 @@ class ConnectorGroup extends Thread implements InvitationTask {
|
|||||||
} finally {
|
} finally {
|
||||||
synchLock.unlock();
|
synchLock.unlock();
|
||||||
}
|
}
|
||||||
for(InvitationListener l : listeners)
|
for (InvitationListener l : listeners)
|
||||||
l.pseudonymExchangeSucceeded(name);
|
l.pseudonymExchangeSucceeded(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pseudonymExchangeFailed() {
|
void pseudonymExchangeFailed() {
|
||||||
for(InvitationListener l : listeners) l.pseudonymExchangeFailed();
|
for (InvitationListener l : listeners) l.pseudonymExchangeFailed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,19 +50,19 @@ class LifecycleManagerImpl implements LifecycleManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void register(Service s) {
|
public void register(Service s) {
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Registering service " + s.getClass().getName());
|
LOG.info("Registering service " + s.getClass().getName());
|
||||||
services.add(s);
|
services.add(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerForShutdown(ExecutorService e) {
|
public void registerForShutdown(ExecutorService e) {
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Registering executor " + e.getClass().getName());
|
LOG.info("Registering executor " + e.getClass().getName());
|
||||||
executors.add(e);
|
executors.add(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
public StartResult startServices() {
|
public StartResult startServices() {
|
||||||
if(!startStopSemaphore.tryAcquire()) {
|
if (!startStopSemaphore.tryAcquire()) {
|
||||||
LOG.info("Already starting or stopping");
|
LOG.info("Already starting or stopping");
|
||||||
return ALREADY_RUNNING;
|
return ALREADY_RUNNING;
|
||||||
}
|
}
|
||||||
@@ -71,35 +71,35 @@ class LifecycleManagerImpl implements LifecycleManager {
|
|||||||
long now = clock.currentTimeMillis();
|
long now = clock.currentTimeMillis();
|
||||||
boolean reopened = db.open();
|
boolean reopened = db.open();
|
||||||
long duration = clock.currentTimeMillis() - now;
|
long duration = clock.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
if(reopened)
|
if (reopened)
|
||||||
LOG.info("Reopening database took " + duration + " ms");
|
LOG.info("Reopening database took " + duration + " ms");
|
||||||
else LOG.info("Creating database took " + duration + " ms");
|
else LOG.info("Creating database took " + duration + " ms");
|
||||||
}
|
}
|
||||||
dbLatch.countDown();
|
dbLatch.countDown();
|
||||||
for(Service s : services) {
|
for (Service s : services) {
|
||||||
now = clock.currentTimeMillis();
|
now = clock.currentTimeMillis();
|
||||||
boolean started = s.start();
|
boolean started = s.start();
|
||||||
duration = clock.currentTimeMillis() - now;
|
duration = clock.currentTimeMillis() - now;
|
||||||
if(!started) {
|
if (!started) {
|
||||||
if(LOG.isLoggable(WARNING)) {
|
if (LOG.isLoggable(WARNING)) {
|
||||||
String name = s.getClass().getName();
|
String name = s.getClass().getName();
|
||||||
LOG.warning(name + " did not start");
|
LOG.warning(name + " did not start");
|
||||||
}
|
}
|
||||||
return SERVICE_ERROR;
|
return SERVICE_ERROR;
|
||||||
}
|
}
|
||||||
if(LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
String name = s.getClass().getName();
|
String name = s.getClass().getName();
|
||||||
LOG.info("Starting " + name + " took " + duration + " ms");
|
LOG.info("Starting " + name + " took " + duration + " ms");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
startupLatch.countDown();
|
startupLatch.countDown();
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
return DB_ERROR;
|
return DB_ERROR;
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
return DB_ERROR;
|
return DB_ERROR;
|
||||||
} finally {
|
} finally {
|
||||||
startStopSemaphore.release();
|
startStopSemaphore.release();
|
||||||
@@ -109,31 +109,31 @@ class LifecycleManagerImpl implements LifecycleManager {
|
|||||||
public void stopServices() {
|
public void stopServices() {
|
||||||
try {
|
try {
|
||||||
startStopSemaphore.acquire();
|
startStopSemaphore.acquire();
|
||||||
} catch(InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.warning("Interrupted while waiting to stop services");
|
LOG.warning("Interrupted while waiting to stop services");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
LOG.info("Stopping services");
|
LOG.info("Stopping services");
|
||||||
eventBus.broadcast(new ShutdownEvent());
|
eventBus.broadcast(new ShutdownEvent());
|
||||||
for(Service s : services) {
|
for (Service s : services) {
|
||||||
boolean stopped = s.stop();
|
boolean stopped = s.stop();
|
||||||
if(LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
String name = s.getClass().getName();
|
String name = s.getClass().getName();
|
||||||
if(stopped) LOG.info("Service stopped: " + name);
|
if (stopped) LOG.info("Service stopped: " + name);
|
||||||
else LOG.warning("Service failed to stop: " + name);
|
else LOG.warning("Service failed to stop: " + name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(ExecutorService e : executors) e.shutdownNow();
|
for (ExecutorService e : executors) e.shutdownNow();
|
||||||
if(LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info(executors.size() + " executors shut down");
|
LOG.info(executors.size() + " executors shut down");
|
||||||
db.close();
|
db.close();
|
||||||
LOG.info("Database closed");
|
LOG.info("Database closed");
|
||||||
shutdownLatch.countDown();
|
shutdownLatch.countDown();
|
||||||
} catch(DbException e) {
|
} catch (DbException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
} finally {
|
} finally {
|
||||||
startStopSemaphore.release();
|
startStopSemaphore.release();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class ShutdownManagerImpl implements ShutdownManager {
|
|||||||
synchLock.lock();
|
synchLock.lock();
|
||||||
try {
|
try {
|
||||||
Thread hook = hooks.remove(handle);
|
Thread hook = hooks.remove(handle);
|
||||||
if(hook == null) return false;
|
if (hook == null) return false;
|
||||||
else return Runtime.getRuntime().removeShutdownHook(hook);
|
else return Runtime.getRuntime().removeShutdownHook(hook);
|
||||||
} finally {
|
} finally {
|
||||||
synchLock.unlock();
|
synchLock.unlock();
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class AuthorFactoryImpl implements AuthorFactory {
|
|||||||
w.writeString(name);
|
w.writeString(name);
|
||||||
w.writeRaw(publicKey);
|
w.writeRaw(publicKey);
|
||||||
w.writeListEnd();
|
w.writeListEnd();
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
// Shouldn't happen with ByteArrayOutputStream
|
// Shouldn't happen with ByteArrayOutputStream
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class AuthorReader implements ObjectReader<Author> {
|
|||||||
// Read and digest the data
|
// Read and digest the data
|
||||||
r.readListStart();
|
r.readListStart();
|
||||||
String name = r.readString(MAX_AUTHOR_NAME_LENGTH);
|
String name = r.readString(MAX_AUTHOR_NAME_LENGTH);
|
||||||
if(name.length() == 0) throw new FormatException();
|
if (name.length() == 0) throw new FormatException();
|
||||||
byte[] publicKey = r.readRaw(MAX_PUBLIC_KEY_LENGTH);
|
byte[] publicKey = r.readRaw(MAX_PUBLIC_KEY_LENGTH);
|
||||||
r.readListEnd();
|
r.readListEnd();
|
||||||
// Reset the reader
|
// Reset the reader
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ class CountingConsumer implements Consumer {
|
|||||||
|
|
||||||
public void write(byte b) throws IOException {
|
public void write(byte b) throws IOException {
|
||||||
count++;
|
count++;
|
||||||
if(count > limit) throw new FormatException();
|
if (count > limit) throw new FormatException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(byte[] b, int off, int len) throws IOException {
|
public void write(byte[] b, int off, int len) throws IOException {
|
||||||
count += len;
|
count += len;
|
||||||
if(count > limit) throw new FormatException();
|
if (count > limit) throw new FormatException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user