Chromium Code Reviews| Index: chrome/android/java/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetector.java |
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetector.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetector.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..1515b41495329a6a7bb92dabe0ced6027809e871 |
| --- /dev/null |
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetector.java |
| @@ -0,0 +1,185 @@ |
| +// Copyright 2016 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.chrome.browser.webapps; |
| + |
| +import org.chromium.base.CommandLine; |
| +import org.chromium.base.ContextUtils; |
| +import org.chromium.base.VisibleForTesting; |
| +import org.chromium.base.annotations.CalledByNative; |
| +import org.chromium.chrome.browser.ChromeSwitches; |
| +import org.chromium.chrome.browser.tab.EmptyTabObserver; |
| +import org.chromium.chrome.browser.tab.Tab; |
| +import org.chromium.content_public.browser.WebContents; |
| + |
| +import java.util.Arrays; |
| +import java.util.HashSet; |
| +import java.util.Set; |
| + |
| +/** |
| + * This class interacts with c++ to detect whether resources in web manifest of a WebAPK has been |
| + * updated. |
| + */ |
| +public class ManifestUpgradeDetector extends EmptyTabObserver { |
| + private long mNativePointer; |
| + private final Tab mTab; |
| + private WebappInfo mWebappInfo; |
| + private Observer mObserver; |
| + private static Boolean sIsEnabled; |
| + private boolean mIsInitialized; |
| + |
| + private static final String TAG = "cr_UpgradeDetector"; |
| + |
| + /** Observes the data fetching pipeline. */ |
| + public interface Observer { |
| + /** Called when the web manifest of the page is available and the icon has been |
| + * downloaded. */ |
| + void onManifestAvaliable(boolean isUpgraded, WebappInfo newInfo, Set<String> iconUrls); |
| + } |
| + |
| + /** |
| + * Sets the observer. |
| + */ |
| + public void setManifestUpgradeDetectorObserver(Observer observer) { |
| + mObserver = observer; |
| + } |
| + |
| + public ManifestUpgradeDetector(Tab tab, WebappInfo info) { |
|
pkotwicz
2016/07/13 01:08:19
Can the observer be passed into the constructor?
Xi Han
2016/07/13 19:25:14
Done.
|
| + mTab = tab; |
| + tab.addObserver(this); |
| + mWebappInfo = info; |
| + String webManifestUrl = info.webManifestUrl(); |
| + if (webManifestUrl == null || webManifestUrl.isEmpty()) return; |
| + mNativePointer = nativeInitialize(mTab.getWebContents(), webManifestUrl); |
| + mIsInitialized = true; |
| + } |
| + |
| + /** |
| + * Updates the status of the native ManifestUpgradeDetector to start the web manifest resources |
| + * fetching pipeline. |
| + */ |
| + public void start() { |
| + if (mIsInitialized) { |
| + nativeStart(mNativePointer); |
| + } |
| + } |
| + |
| + /** |
| + * Puts the object in a state where it is safe to be destroyed. |
| + */ |
| + public void destroy() { |
| + if (mIsInitialized) { |
| + nativeDestroy(mNativePointer); |
| + } |
| + |
| + mObserver = null; |
| + mNativePointer = 0; |
| + } |
| + |
| + @Override |
| + public void onWebContentsSwapped(Tab tab, boolean didStartLoad, |
| + boolean didFinishLoad) { |
| + updatePointers(tab); |
| + } |
| + |
| + @Override |
| + public void onContentChanged(Tab tab) { |
| + updatePointers(tab); |
| + } |
| + |
| + /** |
| + * Updates which WebContents the native ManifestUpgradeDetector is monitoring. |
| + */ |
| + private void updatePointers(Tab tab) { |
| + nativeReplaceWebContents(mNativePointer, tab.getWebContents()); |
| + } |
| + |
| + /** |
| + * Returns whether to enable ManifestUpgradeDetector. |
| + */ |
| + public static boolean isEnabled() { |
| + if (sIsEnabled == null) { |
| + sIsEnabled = CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_WEBAPK); |
| + } |
| + return sIsEnabled; |
| + } |
| + |
| + /** Enables or disables the web manifest upgrade detector for testing. */ |
| + @VisibleForTesting |
| + public static void setIsEnabledForTesting(boolean state) { |
| + sIsEnabled = state; |
| + } |
| + |
| + /** |
| + * Checks whether the new fetched resources match the ones of the current WebAppInfo. |
| + * The changes of start Url, name, background color and so on will lead to request |
| + * updating the installed WebAPK. |
| + */ |
| + @CalledByNative |
| + private void onDataAvailable(String startUrl, String name, String shortName, |
| + String[] iconUrls, int displayMode, int orientation, long themeColor, |
| + long backgroundColor) { |
| + final WebappInfo newInfo = WebappInfo.create(mWebappInfo.id(), startUrl, |
| + null, name, shortName, displayMode, orientation, mWebappInfo.source(), |
| + themeColor, backgroundColor, false, mWebappInfo.webApkPackageName(), |
| + mWebappInfo.webManifestUrl()); |
|
pkotwicz
2016/07/13 01:08:19
We need to validate that the new WebappInfo is Web
Xi Han
2016/07/13 19:25:14
Done.
|
| + final Set<String> iconUrlSet = new HashSet<String>(Arrays.asList(iconUrls)); |
| + if (requireUpgrade(startUrl, newInfo)) { |
| + mWebappInfo = newInfo; |
| + notifyObserver(true, iconUrlSet); |
| + return; |
| + } |
| + mWebappInfo = newInfo; |
| + WebappRegistry.getWebappDataStorage(ContextUtils.getApplicationContext(), mWebappInfo.id(), |
| + new WebappRegistry.FetchWebappDataStorageCallback() { |
| + @Override |
| + public void onWebappDataStorageRetrieved(WebappDataStorage storage) { |
| + onWebappDataRetrieved(storage, iconUrlSet); |
| + } |
| + }); |
| + } |
| + |
| + /** |
| + * Checks whether the new fetched resources match the ones stored in the SharedPreference. |
| + */ |
| + private void onWebappDataRetrieved(WebappDataStorage storage, Set<String> iconUrlSet) { |
| + Set<String> cachedIconUrlsSet = storage.getIconUrls(); |
| + // If icon urls haven't been cached, whether to re-mint WebAPK depends on |
| + // other resources. |
| + boolean isUpgraded = cachedIconUrlsSet == null ? false |
| + : !checkIconUrlSet(cachedIconUrlsSet, iconUrlSet); |
| + |
| + notifyObserver(isUpgraded, iconUrlSet); |
| + } |
| + |
| + /** |
| + * Checks whether attributes, like start Url, app name, background color, are changed. |
| + * {@link mWebappInfo} keeps the latest version of these attributes, so no metadata query is |
| + * needed. These attributes' changes require to re-mint a WebAPK. |
| + */ |
| + private boolean requireUpgrade(String startUrl, WebappInfo newInfo) { |
| + return !mWebappInfo.uri().toString().equals(startUrl) |
| + || !mWebappInfo.name().equals(newInfo.name()) |
|
pkotwicz
2016/07/13 01:08:20
We should check whether the "short_name" is differ
Xi Han
2016/07/13 19:25:14
Done.
|
| + || mWebappInfo.backgroundColor() != newInfo.backgroundColor(); |
| + } |
| + |
| + /** |
| + * Returns whether two icon url sets are equal. |
| + */ |
| + private boolean checkIconUrlSet(Set<String> set, Set<String> anotherSet) { |
| + if (set == null) return anotherSet == null; |
| + return anotherSet != null && set.size() == anotherSet.size() |
| + && set.containsAll(anotherSet); |
| + } |
| + |
| + private void notifyObserver(boolean isUpgraded, Set<String> iconUrls) { |
| + mObserver.onManifestAvaliable(isUpgraded, mWebappInfo, iconUrls); |
| + } |
| + |
| + private native long nativeInitialize(WebContents webContents, String webManifestUrl); |
| + private native void nativeReplaceWebContents(long nativeManifestUpgradeDetector, |
| + WebContents webContents); |
| + private native void nativeDestroy(long nativeManifestUpgradeDetector); |
| + private native void nativeStart(long nativeManifestUpgradeDetector); |
| +} |