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..7b1d2026e1df446a2794e836b2ee4bd34c4cb983 |
--- /dev/null |
+++ b/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkIdentityServiceClient.java |
@@ -0,0 +1,148 @@ |
+// 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, the browser cannot track of WebAPKs which are backed by the browser |
+ * because the browser is not notified if a user changes the runtime host of a WebAPK by |
+ * clearing the WebAPK's data. Besides, the browser loses the knowledge of WebAPKs if a user |
+ * clears the browser's data. Therefore, a browser doesn't know whether it 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); |
+ } |
+ |
+ /** |
+ * Checks whether a WebAPK is backed by the browser with {@link browserContext}. |
+ * @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 { |
+ // The runtime host could be null if the WebAPK hasn't bound to any |
+ // browser yet. |
+ 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 backing browser. |
+ * @param browserPackageName The browser's package name. |
+ * @param webApkBackingBrowserPackageName The package name of the WebAPK's backing 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.equals(webApkBackingBrowserPackageName, browserPackageName)); |
+ } |
+ |
+ /** |
+ * Extracts the backing browser from the WebAPK's meta data. |
+ * See {@link WebApkIdentityServiceClient#SHELL_APK_VERSION_SUPPORTING_SWITCH_RUNTIME_HOST} for |
+ * more details. |
+ */ |
+ private static String maybeExtractRuntimeHostFromMetaData( |
+ Context context, String webApkPackageName) { |
+ Bundle metadata = readMetaData(context, webApkPackageName); |
+ if (metadata == null |
+ || metadata.getInt(WebApkMetaDataKeys.SHELL_APK_VERSION) |
+ >= 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.disconnectAll(appContext); |
+ } |
+} |