Chromium Code Reviews| Index: chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkServiceConnectionManager.java |
| diff --git a/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkServiceConnectionManager.java b/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkServiceConnectionManager.java |
| index 2ef84539ad96a9cd3894c793140645bc647cbfa1..6c2e09f6b371cf2ebfd9fd1c8954251d3a5daa28 100644 |
| --- a/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkServiceConnectionManager.java |
| +++ b/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkServiceConnectionManager.java |
| @@ -12,90 +12,100 @@ import android.os.AsyncTask; |
| import android.os.IBinder; |
| import android.util.Log; |
| -import org.chromium.webapk.lib.runtime_library.IWebApkApi; |
| - |
| import java.util.ArrayList; |
| import java.util.Hashtable; |
| +import java.util.Map; |
| /** |
| - * Manages static global connections between the Chrome application and "WebAPK services". Each |
| - * WebAPK has its own "WebAPK service". |
| + * Each WebAPK has several services. This class manages static global connections between the |
| + * Chrome application and the "WebAPK services." |
| */ |
| public class WebApkServiceConnectionManager { |
| /** |
| - * Interface for getting notified once Chrome is connected to the WebAPK service. |
| + * Interface for getting notified once Chrome is connected to a WebAPK Service. |
| */ |
| public interface ConnectionCallback { |
| /** |
| * Called once Chrome is connected to the WebAPK service. |
| - * @param api The WebAPK service API. |
| + * @param service The WebAPK service. |
| */ |
| - public void onConnected(IWebApkApi api); |
| + void onConnected(IBinder service); |
| } |
| - /** |
| - * Managed connection to WebAPK service. |
| - */ |
| + /** Managed connection to WebAPK service. */ |
| private static class Connection implements ServiceConnection { |
| /** |
| * Whether the connection to the service was established. |
| + * Note: this flag cannot be replaced by checking whether iBinder is null, since the iBinder |
| + * is null even when a service is connected successfully in Junit tests. |
| */ |
| private boolean mHasConnected; |
| - /** |
| - * Callbacks to call once the connection is established. |
| - */ |
| + /** The connection manager who owns this connection. */ |
| + private WebApkServiceConnectionManager mConnectionManager; |
| + |
| + /** Callbacks to call once the connection is established. */ |
| private ArrayList<ConnectionCallback> mCallbacks = new ArrayList<ConnectionCallback>(); |
| - /** |
| - * WebAPK IBinder interface. |
| - */ |
| - private IWebApkApi mApi; |
| + /** WebAPK IBinder interface.*/ |
| + private IBinder mBinder; |
| public boolean hasConnected() { |
| return mHasConnected; |
| } |
| - public IWebApkApi getApi() { |
| - return mApi; |
| + public IBinder getService() { |
| + return mBinder; |
| } |
| public void addCallback(ConnectionCallback callback) { |
| mCallbacks.add(callback); |
| } |
| + public Connection(WebApkServiceConnectionManager manager) { |
| + mConnectionManager = manager; |
| + } |
| + |
| @Override |
| - public void onServiceDisconnected(ComponentName name) {} |
| + public void onServiceDisconnected(ComponentName name) { |
| + mHasConnected = false; |
| + mBinder = null; |
| + if (name != null) { |
| + mConnectionManager.onServiceDisconnected(name.getPackageName()); |
| + } |
| + notifyAndClear(); |
| + } |
| @Override |
| public void onServiceConnected(ComponentName name, IBinder service) { |
| mHasConnected = true; |
| - mApi = IWebApkApi.Stub.asInterface(service); |
| - Log.d(TAG, String.format("Got IWebApkApi: %s", mApi)); |
| + mBinder = service; |
| + Log.d(TAG, String.format("Got IBinder Service: %s", mBinder)); |
| + notifyAndClear(); |
| + } |
| + /** Notifies all the callers either the connection is established or failed to connect. */ |
| + private void notifyAndClear() { |
|
pkotwicz
2017/07/14 23:20:05
You can inline this method in onServiceConnected()
Xi Han
2017/07/17 20:45:32
Done.
|
| for (ConnectionCallback callback : mCallbacks) { |
| - callback.onConnected(mApi); |
| + callback.onConnected(mBinder); |
| } |
| mCallbacks.clear(); |
| } |
| } |
| - private static final String CATEGORY_WEBAPK_API = "android.intent.category.WEBAPK_API"; |
| - |
| - private static final String TAG = "cr_WebApk"; |
| + private static final String TAG = "cr_WebApkService"; |
| - private static WebApkServiceConnectionManager sInstance; |
| + /** The category of the service to connect. */ |
| + private String mCategory; |
| - /** |
| - * Mapping of WebAPK package to WebAPK service connection. |
| - */ |
| + /** Mapping of WebAPK package to WebAPK service connection.*/ |
| private Hashtable<String, Connection> mConnections = new Hashtable<String, Connection>(); |
| - public static WebApkServiceConnectionManager getInstance() { |
| - if (sInstance == null) { |
| - sInstance = new WebApkServiceConnectionManager(); |
| - } |
| - return sInstance; |
| + /** Called when a WebAPK Service connection is disconnected. */ |
| + protected void onServiceDisconnected(String webApkName) { |
| + // TODO(hanxi): checks whether to kill the corresponding WebApkActivity if the WebAPK's data |
| + // is cleared or the WebAPK is uninstalled. |
| + mConnections.remove(webApkName); |
| } |
| /** |
| @@ -103,36 +113,60 @@ public class WebApkServiceConnectionManager { |
| * @param appContext Application context. |
| * @param webApkPackage WebAPK package to create connection for. |
| * @param callback Callback to call after connection has been established. Called synchronously |
| - * if the connection is already established. |
| */ |
| public void connect(final Context appContext, final String webApkPackage, |
| final ConnectionCallback callback) { |
| Connection connection = mConnections.get(webApkPackage); |
| if (connection != null) { |
| if (connection.hasConnected()) { |
| - callback.onConnected(connection.getApi()); |
| + callback.onConnected(connection.getService()); |
| } else { |
| connection.addCallback(callback); |
| } |
| return; |
| } |
| - new AsyncTask<Void, Void, Void>() { |
| + new AsyncTask<Void, Void, Boolean>() { |
| @Override |
| - protected Void doInBackground(Void... params) { |
| - Connection newConnection = new Connection(); |
| + protected Boolean doInBackground(Void... params) { |
| + Connection newConnection = new Connection(WebApkServiceConnectionManager.this); |
| newConnection.addCallback(callback); |
| Intent intent = createConnectIntent(webApkPackage); |
| - |
| + boolean success = false; |
| try { |
| - appContext.bindService(intent, newConnection, Context.BIND_AUTO_CREATE); |
| - |
| + success = |
| + appContext.bindService(intent, newConnection, Context.BIND_AUTO_CREATE); |
| } catch (SecurityException e) { |
| Log.w(TAG, "Security failed binding.", e); |
| - return null; |
| + } finally { |
|
pkotwicz
2017/07/14 23:20:05
Does this need to be in a finally{} block?
Xi Han
2017/07/17 20:45:32
Done.
|
| + if (success) { |
| + mConnections.put(webApkPackage, newConnection); |
| + } |
| + return success; |
| } |
| + } |
| + |
| + @Override |
| + protected void onPostExecute(Boolean success) { |
| + if (!success) callback.onConnected(null); |
| + } |
| + }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); |
| + } |
| - mConnections.put(webApkPackage, newConnection); |
| + /** |
| + * Disconnect from all of the WebAPK services. Can be called from any thread. |
| + * @param appContext The application context. |
| + */ |
| + public void disconnect(final Context appContext) { |
| + new AsyncTask<Void, Void, Void>() { |
| + @Override |
| + protected Void doInBackground(Void... voids) { |
| + for (Map.Entry<String, Connection> entry : mConnections.entrySet()) { |
| + Connection connection = entry.getValue(); |
| + if (connection == null || !connection.hasConnected()) continue; |
|
pkotwicz
2017/07/14 23:20:05
- Isn't it impossible for |connection| to be null?
Xi Han
2017/07/17 20:45:32
Removed this check.
|
| + appContext.unbindService(connection); |
| + } |
| + mConnections.clear(); |
| return null; |
| } |
| }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); |
| @@ -162,16 +196,17 @@ public class WebApkServiceConnectionManager { |
| }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); |
| } |
| - WebApkServiceConnectionManager() { |
| + WebApkServiceConnectionManager(String category) { |
| + mCategory = category; |
| } |
| /** |
| * Creates intent to connect to WebAPK service. |
| * @param webApkPackage The package name of the WebAPK to connect to. |
| */ |
| - private static Intent createConnectIntent(String webApkPackage) { |
| + private Intent createConnectIntent(String webApkPackage) { |
| Intent intent = new Intent(); |
| - intent.addCategory(CATEGORY_WEBAPK_API); |
| + intent.addCategory(mCategory); |
| intent.setPackage(webApkPackage); |
| return intent; |
| } |