diff --git a/briar-android/src/org/briarproject/android/AndroidNotificationManagerImpl.java b/briar-android/src/org/briarproject/android/AndroidNotificationManagerImpl.java index 9ba3f6792fd4b025b60db54a974a8a0aa8be8d55..966de01db949176bda374f03248e51174c1c0b88 100644 --- a/briar-android/src/org/briarproject/android/AndroidNotificationManagerImpl.java +++ b/briar-android/src/org/briarproject/android/AndroidNotificationManagerImpl.java @@ -9,6 +9,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; import android.os.Build; +import android.support.annotation.UiThread; import android.support.v4.app.NotificationCompat; import android.support.v4.app.TaskStackBuilder; @@ -105,7 +106,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, private final BroadcastReceiver receiver = new DeleteIntentReceiver(); private final AtomicBoolean used = new AtomicBoolean(false); - // The following must only be accessed on the AndroidExecutor thread + // The following must only be accessed on the main UI thread private final Map<GroupId, Integer> contactCounts = new HashMap<>(); private final Map<GroupId, Integer> forumCounts = new HashMap<>(); private final Map<GroupId, Integer> blogCounts = new HashMap<>(); @@ -139,7 +140,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, throw new ServiceException(e); } // Register a broadcast receiver for notifications being dismissed - Future<Void> f = androidExecutor.submit(new Callable<Void>() { + Future<Void> f = androidExecutor.runOnUiThread(new Callable<Void>() { @Override public Void call() { IntentFilter filter = new IntentFilter(); @@ -161,7 +162,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, @Override public void stopService() throws ServiceException { // Clear all notifications and unregister the broadcast receiver - Future<Void> f = androidExecutor.submit(new Callable<Void>() { + Future<Void> f = androidExecutor.runOnUiThread(new Callable<Void>() { @Override public Void call() { clearPrivateMessageNotification(); @@ -179,6 +180,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, } } + @UiThread private void clearPrivateMessageNotification() { contactCounts.clear(); contactTotal = 0; @@ -187,6 +189,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, nm.cancel(PRIVATE_MESSAGE_NOTIFICATION_ID); } + @UiThread private void clearForumPostNotification() { forumCounts.clear(); forumTotal = 0; @@ -195,6 +198,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, nm.cancel(FORUM_POST_NOTIFICATION_ID); } + @UiThread private void clearBlogPostNotification() { blogCounts.clear(); blogTotal = 0; @@ -203,6 +207,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, nm.cancel(BLOG_POST_NOTIFICATION_ID); } + @UiThread private void clearIntroductionSuccessNotification() { introductionTotal = 0; Object o = appContext.getSystemService(NOTIFICATION_SERVICE); @@ -256,7 +261,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, } private void showPrivateMessageNotification(final GroupId g) { - androidExecutor.execute(new Runnable() { + androidExecutor.runOnUiThread(new Runnable() { @Override public void run() { if (blockContacts) return; @@ -272,7 +277,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, @Override public void clearPrivateMessageNotification(final GroupId g) { - androidExecutor.execute(new Runnable() { + androidExecutor.runOnUiThread(new Runnable() { @Override public void run() { Integer count = contactCounts.remove(g); @@ -283,6 +288,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, }); } + @UiThread private void updatePrivateMessageNotification() { if (contactTotal == 0) { clearPrivateMessageNotification(); @@ -339,6 +345,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, } } + @UiThread private int getDefaults() { int defaults = DEFAULT_LIGHTS; boolean sound = settings.getBoolean("notifySound", true); @@ -352,7 +359,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, @Override public void clearAllContactNotifications() { - androidExecutor.execute(new Runnable() { + androidExecutor.runOnUiThread(new Runnable() { @Override public void run() { clearPrivateMessageNotification(); @@ -361,8 +368,9 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, }); } + @UiThread private void showForumPostNotification(final GroupId g) { - androidExecutor.execute(new Runnable() { + androidExecutor.runOnUiThread(new Runnable() { @Override public void run() { if (blockForums) return; @@ -378,7 +386,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, @Override public void clearForumPostNotification(final GroupId g) { - androidExecutor.execute(new Runnable() { + androidExecutor.runOnUiThread(new Runnable() { @Override public void run() { Integer count = forumCounts.remove(g); @@ -389,6 +397,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, }); } + @UiThread private void updateForumPostNotification() { if (forumTotal == 0) { clearForumPostNotification(); @@ -446,7 +455,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, @Override public void clearAllForumPostNotifications() { - androidExecutor.execute(new Runnable() { + androidExecutor.runOnUiThread(new Runnable() { @Override public void run() { clearForumPostNotification(); @@ -454,8 +463,9 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, }); } + @UiThread private void showBlogPostNotification(final GroupId g) { - androidExecutor.execute(new Runnable() { + androidExecutor.runOnUiThread(new Runnable() { @Override public void run() { if (blockBlogs) return; @@ -471,7 +481,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, @Override public void clearBlogPostNotification(final GroupId g) { - androidExecutor.execute(new Runnable() { + androidExecutor.runOnUiThread(new Runnable() { @Override public void run() { Integer count = blogCounts.remove(g); @@ -482,6 +492,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, }); } + @UiThread private void updateBlogPostNotification() { if (blogTotal == 0) { clearBlogPostNotification(); @@ -525,7 +536,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, @Override public void clearAllBlogPostNotifications() { - androidExecutor.execute(new Runnable() { + androidExecutor.runOnUiThread(new Runnable() { @Override public void run() { clearBlogPostNotification(); @@ -534,7 +545,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, } private void showIntroductionNotification() { - androidExecutor.execute(new Runnable() { + androidExecutor.runOnUiThread(new Runnable() { @Override public void run() { if (blockIntroductions) return; @@ -544,6 +555,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, }); } + @UiThread private void updateIntroductionNotification() { NotificationCompat.Builder b = new NotificationCompat.Builder(appContext); @@ -583,7 +595,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, @Override public void blockNotification(final GroupId g) { - androidExecutor.execute(new Runnable() { + androidExecutor.runOnUiThread(new Runnable() { @Override public void run() { blockedGroup = g; @@ -593,7 +605,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, @Override public void unblockNotification(final GroupId g) { - androidExecutor.execute(new Runnable() { + androidExecutor.runOnUiThread(new Runnable() { @Override public void run() { if (g.equals(blockedGroup)) blockedGroup = null; @@ -603,7 +615,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, @Override public void blockAllContactNotifications() { - androidExecutor.execute(new Runnable() { + androidExecutor.runOnUiThread(new Runnable() { @Override public void run() { blockContacts = true; @@ -614,7 +626,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, @Override public void unblockAllContactNotifications() { - androidExecutor.execute(new Runnable() { + androidExecutor.runOnUiThread(new Runnable() { @Override public void run() { blockContacts = false; @@ -625,7 +637,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, @Override public void blockAllForumPostNotifications() { - androidExecutor.execute(new Runnable() { + androidExecutor.runOnUiThread(new Runnable() { @Override public void run() { blockForums = true; @@ -635,7 +647,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, @Override public void unblockAllForumPostNotifications() { - androidExecutor.execute(new Runnable() { + androidExecutor.runOnUiThread(new Runnable() { @Override public void run() { blockForums = false; @@ -645,7 +657,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, @Override public void blockAllBlogPostNotifications() { - androidExecutor.execute(new Runnable() { + androidExecutor.runOnUiThread(new Runnable() { @Override public void run() { blockBlogs = true; @@ -655,7 +667,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, @Override public void unblockAllBlogPostNotifications() { - androidExecutor.execute(new Runnable() { + androidExecutor.runOnUiThread(new Runnable() { @Override public void run() { blockBlogs = false; @@ -683,7 +695,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); - androidExecutor.execute(new Runnable() { + androidExecutor.runOnUiThread(new Runnable() { @Override public void run() { if (CLEAR_PRIVATE_MESSAGE_ACTION.equals(action)) { diff --git a/briar-android/src/org/briarproject/android/BriarService.java b/briar-android/src/org/briarproject/android/BriarService.java index 33d69c8f68e2a6ed7144d4e69014b51b7f783531..f03751821ddcc5886cb31715e32ffc9f1896140e 100644 --- a/briar-android/src/org/briarproject/android/BriarService.java +++ b/briar-android/src/org/briarproject/android/BriarService.java @@ -108,7 +108,8 @@ public class BriarService extends Service { } private void showStartupFailureNotification(final StartResult result) { - androidExecutor.execute(new Runnable() { + androidExecutor.runOnUiThread(new Runnable() { + @Override public void run() { NotificationCompat.Builder b = new NotificationCompat.Builder(BriarService.this); @@ -197,11 +198,13 @@ public class BriarService extends Service { private volatile IBinder binder = null; + @Override public void onServiceConnected(ComponentName name, IBinder binder) { this.binder = binder; binderLatch.countDown(); } + @Override public void onServiceDisconnected(ComponentName name) {} /** Waits for the service to connect and returns its binder. */ diff --git a/briar-android/src/org/briarproject/android/SplashScreenActivity.java b/briar-android/src/org/briarproject/android/SplashScreenActivity.java index c933f637e7d33f96039493fa64e3047d4fb1cee3..12c0533c7647053de0405c84f9f4987b06c549ab 100644 --- a/briar-android/src/org/briarproject/android/SplashScreenActivity.java +++ b/briar-android/src/org/briarproject/android/SplashScreenActivity.java @@ -87,7 +87,7 @@ public class SplashScreenActivity extends BaseActivity { } private void setPreferencesDefaults() { - androidExecutor.execute(new Runnable() { + androidExecutor.runOnBackgroundThread(new Runnable() { @Override public void run() { PreferenceManager.setDefaultValues(SplashScreenActivity.this, diff --git a/briar-android/src/org/briarproject/android/api/AndroidExecutor.java b/briar-android/src/org/briarproject/android/api/AndroidExecutor.java index 047a74c14701e85a174f0acc9e78a16038aab638..7ea06bc2bd020841367da67fc2cb27b73367a911 100644 --- a/briar-android/src/org/briarproject/android/api/AndroidExecutor.java +++ b/briar-android/src/org/briarproject/android/api/AndroidExecutor.java @@ -13,10 +13,21 @@ public interface AndroidExecutor { * Runs the given task on a background thread with a message queue and * returns a Future for getting the result. */ - <V> Future<V> submit(Callable<V> c); + <V> Future<V> runOnBackgroundThread(Callable<V> c); /** * Runs the given task on a background thread with a message queue. */ - void execute(Runnable r); + void runOnBackgroundThread(Runnable r); + + /** + * Runs the given task on the main UI thread and returns a Future for + * getting the result. + */ + <V> Future<V> runOnUiThread(Callable<V> c); + + /** + * Runs the given task on the main UI thread. + */ + void runOnUiThread(Runnable r); } diff --git a/briar-android/src/org/briarproject/android/fragment/SettingsFragment.java b/briar-android/src/org/briarproject/android/fragment/SettingsFragment.java index 7bde67e6e224a2051ffd83421c5ee96ea99a150b..5b768aaa1a1370b7b83c7bc5f9ce67a2af229ec7 100644 --- a/briar-android/src/org/briarproject/android/fragment/SettingsFragment.java +++ b/briar-android/src/org/briarproject/android/fragment/SettingsFragment.java @@ -173,6 +173,7 @@ public class SettingsFragment extends PreferenceFragmentCompat private void loadSettings() { listener.runOnDbThread(new Runnable() { + @Override public void run() { try { long now = System.currentTimeMillis(); @@ -195,6 +196,7 @@ public class SettingsFragment extends PreferenceFragmentCompat private void displaySettings() { listener.runOnUiThread(new Runnable() { + @Override public void run() { enableBluetooth.setValue(Boolean.toString(bluetoothSetting)); torOverMobile.setValue(Boolean.toString(torSetting)); @@ -228,7 +230,8 @@ public class SettingsFragment extends PreferenceFragmentCompat } private void triggerFeedback() { - androidExecutor.execute(new Runnable() { + androidExecutor.runOnBackgroundThread(new Runnable() { + @Override public void run() { ACRA.getErrorReporter().handleException(new UserFeedback(), false); @@ -268,7 +271,8 @@ public class SettingsFragment extends PreferenceFragmentCompat private void enableOrDisableBluetooth(final boolean enable) { final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (adapter != null) { - androidExecutor.execute(new Runnable() { + androidExecutor.runOnBackgroundThread(new Runnable() { + @Override public void run() { if (enable) adapter.enable(); else adapter.disable(); @@ -279,6 +283,7 @@ public class SettingsFragment extends PreferenceFragmentCompat private void storeTorSettings() { listener.runOnDbThread(new Runnable() { + @Override public void run() { try { Settings s = new Settings(); @@ -298,6 +303,7 @@ public class SettingsFragment extends PreferenceFragmentCompat private void storeBluetoothSettings() { listener.runOnDbThread(new Runnable() { + @Override public void run() { try { Settings s = new Settings(); @@ -317,6 +323,7 @@ public class SettingsFragment extends PreferenceFragmentCompat private void storeSettings(final Settings settings) { listener.runOnDbThread(new Runnable() { + @Override public void run() { try { long now = System.currentTimeMillis(); diff --git a/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java b/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java index 2ea18075dc29ee444884047e1914b2f16c4181b3..82fca3e36d63c587eac49ee6e7edabe278b00437 100644 --- a/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java +++ b/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java @@ -144,7 +144,7 @@ public class ShowQrCodeFragment extends BaseEventFragment final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (adapter != null && !adapter.isEnabled()) { waitingForBluetooth = true; - androidExecutor.execute(new Runnable() { + androidExecutor.runOnBackgroundThread(new Runnable() { @Override public void run() { adapter.enable(); diff --git a/briar-android/src/org/briarproject/android/panic/PanicResponderActivity.java b/briar-android/src/org/briarproject/android/panic/PanicResponderActivity.java index ff3ba954a7f0580b71cb196a020ce368f383287d..ba8583fcac04e9cf99c11a27569251e42ad1a5a4 100644 --- a/briar-android/src/org/briarproject/android/panic/PanicResponderActivity.java +++ b/briar-android/src/org/briarproject/android/panic/PanicResponderActivity.java @@ -107,7 +107,7 @@ public class PanicResponderActivity extends BriarActivity { } private void deleteAllData() { - androidExecutor.execute(new Runnable() { + androidExecutor.runOnBackgroundThread(new Runnable() { @Override public void run() { configController.deleteAccount(PanicResponderActivity.this); diff --git a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java index 8c26d4518e330982194ad796cd6eef4d89240801..d5c0ca5bc1609eb0f95356571020a461849e5080 100644 --- a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java +++ b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java @@ -125,12 +125,13 @@ class DroidtoothPlugin implements DuplexPlugin { // BluetoothAdapter.getDefaultAdapter() must be called on a thread // with a message queue, so submit it to the AndroidExecutor try { - adapter = androidExecutor.submit(new Callable<BluetoothAdapter>() { - @Override - public BluetoothAdapter call() throws Exception { - return BluetoothAdapter.getDefaultAdapter(); - } - }).get(); + adapter = androidExecutor.runOnBackgroundThread( + new Callable<BluetoothAdapter>() { + @Override + public BluetoothAdapter call() throws Exception { + return BluetoothAdapter.getDefaultAdapter(); + } + }).get(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new IOException("Interrupted while getting BluetoothAdapter"); diff --git a/briar-android/src/org/briarproject/system/AndroidExecutorImpl.java b/briar-android/src/org/briarproject/system/AndroidExecutorImpl.java index 07b6e69e5e89e656e0b61290c551dd1d3b09b3b8..180881febac82ce3d888998f3ac31cbd65bb9893 100644 --- a/briar-android/src/org/briarproject/system/AndroidExecutorImpl.java +++ b/briar-android/src/org/briarproject/system/AndroidExecutorImpl.java @@ -1,5 +1,6 @@ package org.briarproject.system; +import android.app.Application; import android.os.Handler; import android.os.Looper; @@ -16,18 +17,21 @@ import javax.inject.Inject; class AndroidExecutorImpl implements AndroidExecutor { + private final Handler uiHandler; private final Runnable loop; private final AtomicBoolean started = new AtomicBoolean(false); private final CountDownLatch startLatch = new CountDownLatch(1); - private volatile Handler handler = null; + private volatile Handler backgroundHandler = null; @Inject - AndroidExecutorImpl() { + AndroidExecutorImpl(Application app) { + uiHandler = new Handler(app.getApplicationContext().getMainLooper()); loop = new Runnable() { + @Override public void run() { Looper.prepare(); - handler = new Handler(); + backgroundHandler = new Handler(); startLatch.countDown(); Looper.loop(); } @@ -46,14 +50,28 @@ class AndroidExecutorImpl implements AndroidExecutor { } } - public <V> Future<V> submit(Callable<V> c) { + @Override + public <V> Future<V> runOnBackgroundThread(Callable<V> c) { FutureTask<V> f = new FutureTask<>(c); - execute(f); + runOnBackgroundThread(f); return f; } - public void execute(Runnable r) { + @Override + public void runOnBackgroundThread(Runnable r) { startIfNecessary(); - handler.post(r); + backgroundHandler.post(r); + } + + @Override + public <V> Future<V> runOnUiThread(Callable<V> c) { + FutureTask<V> f = new FutureTask<>(c); + runOnUiThread(f); + return f; + } + + @Override + public void runOnUiThread(Runnable r) { + uiHandler.post(r); } } diff --git a/briar-android/src/org/briarproject/system/AndroidSystemModule.java b/briar-android/src/org/briarproject/system/AndroidSystemModule.java index a577ac7c3e1c4d787f80b22d44a406bcb4b170a1..99ca8fb7abf5a18feb793e9dbf1dd3ddeda1929f 100644 --- a/briar-android/src/org/briarproject/system/AndroidSystemModule.java +++ b/briar-android/src/org/briarproject/system/AndroidSystemModule.java @@ -27,7 +27,7 @@ public class AndroidSystemModule { @Provides @Singleton - public AndroidExecutor provideAndroidExecutor() { - return new AndroidExecutorImpl(); + public AndroidExecutor provideAndroidExecutor(Application app) { + return new AndroidExecutorImpl(app); } }