Remove the synchronization
All of the callbacks happen on the same thread; no need to
synchronize. Also move away from TimerTask and use Handler to post
the termination callback.
Change-Id: If684e29686f2c7557cc56057c7f1ec6a1dfd3bcb
diff --git a/src/com/android/telecomm/CallServiceFinder.java b/src/com/android/telecomm/CallServiceFinder.java
index 43e2485..fa5ee14 100644
--- a/src/com/android/telecomm/CallServiceFinder.java
+++ b/src/com/android/telecomm/CallServiceFinder.java
@@ -23,8 +23,9 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.os.Handler;
import android.os.IBinder;
-import android.os.Bundle;
+import android.os.Looper;
import android.os.RemoteException;
import android.telecomm.ICallService;
import android.telecomm.ICallServiceLookupResponse;
@@ -37,8 +38,6 @@
import java.util.List;
import java.util.Set;
-import java.util.Timer;
-import java.util.TimerTask;
/**
* Finds {@link ICallService} and {@link ICallServiceProvider} implementations on the device.
@@ -111,49 +110,40 @@
* @param registrar The registrar with which to register and unregister this provider.
*/
ProviderWrapper(Context context, final ProviderRegistrar registrar) {
- ComponentName name = registrar.getProviderName();
- Preconditions.checkNotNull(name);
- Preconditions.checkNotNull(context);
+ ComponentName name = registrar.getProviderName();
+ Preconditions.checkNotNull(name);
+ Preconditions.checkNotNull(context);
- Intent serviceIntent = new Intent(CALL_SERVICE_PROVIDER_CLASS_NAME).setComponent(name);
- Log.i(TAG, "Binding to ICallServiceProvider through " + serviceIntent);
+ Intent serviceIntent = new Intent(CALL_SERVICE_PROVIDER_CLASS_NAME).setComponent(name);
+ Log.i(TAG, "Binding to ICallServiceProvider through " + serviceIntent);
- // Connection object for the service binding.
- ServiceConnection connection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName className, IBinder service) {
- registrar.register(ICallServiceProvider.Stub.asInterface(service));
- }
+ // Connection object for the service binding.
+ ServiceConnection connection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ registrar.register(ICallServiceProvider.Stub.asInterface(service));
+ }
- @Override
- public void onServiceDisconnected(ComponentName className) {
- registrar.unregister();
- }
- };
+ @Override
+ public void onServiceDisconnected(ComponentName className) {
+ registrar.unregister();
+ }
+ };
- if (!context.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) {
- // TODO(santoscordon): Handle error.
- }
- }
- }
-
- /**
- * A timer task to ensure each lookup cycle is time-bound, see LOOKUP_TIMEOUT.
- */
- private class LookupTerminator extends TimerTask {
- @Override
- public void run() {
- terminateLookup();
+ if (!context.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) {
+ // TODO(santoscordon): Handle error.
+ }
}
}
private static final String TAG = CallServiceFinder.class.getSimpleName();
/**
- * The longest period in milliseconds each lookup cycle is allowed to span over, see mTimer.
+ * The longest period in milliseconds each lookup cycle is allowed to span over, see
+ * {@link #mLookupTerminator}.
* TODO(gilad): Likely requires tuning.
*/
- private static final int LOOKUP_TIMEOUT = 100;
+ private static final int LOOKUP_TIMEOUT_MS = 100;
/**
* Used to retrieve all known ICallServiceProvider implementations from the framework.
@@ -195,7 +185,15 @@
* Used to interrupt lookup cycles that didn't terminate naturally within the allowed
* period, see LOOKUP_TIMEOUT.
*/
- private Timer mTimer;
+ private final Runnable mLookupTerminator = new Runnable() {
+ @Override
+ public void run() {
+ terminateLookup();
+ }
+ };
+
+ /** Used to run code (e.g. messages, Runnables) on the main (UI) thread. */
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
/**
* Persists the specified parameters.
@@ -207,12 +205,13 @@
}
/**
- * Initiates a lookup cycle for call-service providers.
+ * Initiates a lookup cycle for call-service providers. Must be called from the UI thread.
* TODO(gilad): Expand this comment to describe the lookup flow in more detail.
*
* @param context The relevant application context.
*/
- synchronized void initiateLookup(Context context) {
+ void initiateLookup(Context context) {
+ ThreadUtil.checkOnMainThread();
if (mIsLookupInProgress) {
// At most one active lookup is allowed at any given time, bail out.
return;
@@ -250,14 +249,9 @@
// back to the switchboard.
updateSwitchboard();
} else {
- // Start the timeout for this lookup cycle.
- // TODO(gilad): Consider reusing the same timer instead of creating new ones.
- if (mTimer != null) {
- // Shouldn't be running but better safe than sorry.
- mTimer.cancel();
- }
- mTimer = new Timer();
- mTimer.schedule(new LookupTerminator(), LOOKUP_TIMEOUT);
+ // Schedule a lookup terminator to run after LOOKUP_TIMEOUT_MS milliseconds.
+ mHandler.removeCallbacks(mLookupTerminator);
+ mHandler.postDelayed(mLookupTerminator, LOOKUP_TIMEOUT_MS);
}
}
@@ -361,9 +355,7 @@
* Timeouts the current lookup cycle, see LookupTerminator.
*/
private void terminateLookup() {
- if (mTimer != null) {
- mTimer.cancel(); // Terminate the timer thread.
- }
+ mHandler.removeCallbacks(mLookupTerminator);
updateSwitchboard();
mIsLookupInProgress = false;
@@ -374,9 +366,8 @@
* to call-service providers).
*/
private void updateSwitchboard() {
- synchronized (mProviderRegistry) {
- // TODO(gilad): More here.
- mSwitchboard.setCallServices(null);
- }
+ ThreadUtil.checkOnMainThread();
+ // TODO(gilad): More here.
+ mSwitchboard.setCallServices(null);
}
}