Chromium Code Reviews| Index: chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkIdentityServiceClient.java |
| diff --git a/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkIdentityServiceClient.java b/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkIdentityServiceClient.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..46d7a8cd74140acbe68c081272d08f88276723c6 |
| --- /dev/null |
| +++ b/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkIdentityServiceClient.java |
| @@ -0,0 +1,150 @@ |
| +// Copyright 2017 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +package org.chromium.webapk.lib.client; |
| + |
| +import android.content.Context; |
| +import android.content.pm.ApplicationInfo; |
| +import android.content.pm.PackageManager; |
| +import android.os.Bundle; |
| +import android.os.IBinder; |
| +import android.os.RemoteException; |
| +import android.text.TextUtils; |
| +import android.util.Log; |
| + |
| +import org.chromium.webapk.lib.common.WebApkMetaDataKeys; |
| +import org.chromium.webapk.lib.common.identity_service.IIdentityService; |
| + |
| +/** |
| + * Provides APIs for browsers to communicate with WebAPK Identity services. Each WebAPK has its own |
| + * "WebAPK Identity service". |
| + */ |
| +public class WebApkIdentityServiceClient { |
| + /** Used to notify the consumer after checking whether the caller browser backs the WebAPK. */ |
| + public interface CheckBrowserBacksWebApkCallback { |
| + void onChecked(boolean doesBrowserBackWebApk); |
| + } |
| + |
| + /** |
| + * Before shell APK version 6, all WebAPKs are installed from browsers, and that browser is the |
| + * runtime host and specified in the WebAPK's AndroidManifest.xml. In shell APK version 6, we |
| + * introduced logic to allow user to choose runtime host browser for WebAPKs not bound to any |
| + * browser, and for WebAPKs installed from browsers when the browser is subsequently |
| + * uninstalled. However, user can either clear WebAPK's data that may require to choose a |
| + * runtime host again, or clear a browser's data that makes the browser loses its knowledge of |
| + * owned WebAPKs. Therefore, we don't know exactly which browser is the runtime host of a WebAPK |
| + * without asking the WebAPK. An Identity service is introduced in shell APK version 16 to allow |
| + * browsers to query the runtime host of a WebAPK. |
| + */ |
| + public static final int SHELL_APK_VERSION_SUPPORTING_SWITCH_RUNTIME_HOST = 6; |
| + |
| + private static final String ACTION_WEBAPK_IDENTITY_SERVICE = "org.webapk.IDENTITY_SERVICE_API"; |
| + private static final String TAG = "cr_WebApkIdentityService"; |
| + |
| + private static WebApkIdentityServiceClient sInstance; |
| + |
| + /** Manages connections between the browser application and WebAPK Identity services. */ |
| + private WebApkServiceConnectionManager mConnectionManager; |
| + |
| + public static WebApkIdentityServiceClient getInstance() { |
| + if (sInstance == null) { |
| + sInstance = new WebApkIdentityServiceClient(); |
| + } |
| + return sInstance; |
| + } |
| + |
| + private WebApkIdentityServiceClient() { |
| + mConnectionManager = new WebApkServiceConnectionManager( |
| + null /* category */, ACTION_WEBAPK_IDENTITY_SERVICE); |
| + } |
| + |
| + public WebApkServiceConnectionManager getConnectionManagerForTesting() { |
| + return mConnectionManager; |
| + } |
| + |
| + /** |
| + * Checks the runtime host of a WebAPK and notifies the caller. The runtime host could be null |
| + * if the WebAPK either doesn't have an Identity service or hasn't bind to any browser yet. |
| + * @param browserContext The browser context. |
| + * @param webApkPackageName The package name of the WebAPK. |
| + * @param callback The callback to be called after querying the runtime host is done. |
| + */ |
| + public void checkBrowserBacksWebApkAsync(final Context browserContext, |
| + final String webApkPackageName, final CheckBrowserBacksWebApkCallback callback) { |
| + WebApkServiceConnectionManager.ConnectionCallback connectionCallback = |
| + new WebApkServiceConnectionManager.ConnectionCallback() { |
| + @Override |
| + public void onConnected(IBinder service) { |
| + String browserPackageName = browserContext.getPackageName(); |
| + if (service == null) { |
| + onGotWebApkRuntimeHost(browserPackageName, |
| + maybeExtractRuntimeHostFromMetaData( |
| + browserContext, webApkPackageName), |
| + callback); |
| + return; |
| + } |
| + |
| + IIdentityService identityService = |
| + IIdentityService.Stub.asInterface(service); |
| + String runtimeHost = null; |
| + try { |
| + runtimeHost = identityService.getRuntimeHostBrowserPackageName(); |
| + } catch (RemoteException e) { |
| + Log.w(TAG, "Failed to get runtime host from the Identity service."); |
| + } |
| + onGotWebApkRuntimeHost(browserPackageName, runtimeHost, callback); |
| + } |
| + }; |
| + mConnectionManager.connect(browserContext, webApkPackageName, connectionCallback); |
| + } |
| + |
| + /** |
| + * Called after fetching the WebAPK's runtime host browser. |
| + * @param browserPackageName The browser's package name. |
| + * @param webApkBackingBrowserPackageName The package name of the WebAPK's runtime host browser. |
| + * @param callback The callback to notify whether {@link browserPackageName} backs the WebAPK. |
| + */ |
| + private static void onGotWebApkRuntimeHost(String browserPackageName, |
| + String webApkBackingBrowserPackageName, CheckBrowserBacksWebApkCallback callback) { |
| + callback.onChecked(!TextUtils.isEmpty(webApkBackingBrowserPackageName) |
| + && webApkBackingBrowserPackageName.contentEquals(browserPackageName)); |
|
pkotwicz
2017/07/20 01:32:05
Can you use TextUtils#equals() here?
Xi Han
2017/07/21 20:36:35
Done.
|
| + } |
| + |
| + /** |
| + * Extracts the backing browser from the WebAPK's meta data. |
| + * See {@link WebApkIdentityServiceClient#SHELL_APK_VERSION_SUPPORTING_SWITCH_RUNTIME_HOST} for |
| + * more details. |
| + */ |
| + public static String maybeExtractRuntimeHostFromMetaData( |
| + Context context, String webApkPackageName) { |
| + Bundle metadata = readMetaData(context, webApkPackageName); |
| + if (metadata.getInt(WebApkMetaDataKeys.SHELL_APK_VERSION) |
|
pkotwicz
2017/07/21 19:24:27
In case you haven't done so, you need to add a nul
Xi Han
2017/07/21 20:36:35
Done.
|
| + >= SHELL_APK_VERSION_SUPPORTING_SWITCH_RUNTIME_HOST) { |
| + // The backing browser in the WebAPK's meta data may not be the one which actually backs |
| + // the WebAPK. The user may have switched the backing browser. |
| + return null; |
| + } |
| + |
| + return metadata.getString(WebApkMetaDataKeys.RUNTIME_HOST); |
| + } |
| + |
| + /** Returns the <meta-data> in the Android Manifest of the given package name. */ |
| + private static Bundle readMetaData(Context context, String packageName) { |
| + ApplicationInfo ai = null; |
| + try { |
| + ai = context.getPackageManager().getApplicationInfo( |
| + packageName, PackageManager.GET_META_DATA); |
| + } catch (PackageManager.NameNotFoundException e) { |
| + return null; |
| + } |
| + return ai.metaData; |
| + } |
| + |
| + /** Disconnects all the connections to WebAPK Identity services. */ |
| + public static void disconnectAll(Context appContext) { |
| + if (sInstance == null) return; |
| + |
| + sInstance.mConnectionManager.disconnect(appContext); |
| + } |
| +} |