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..3487beb46a71c9e1531ee85869dcb9d1550732d6 |
| --- /dev/null |
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetector.java |
| @@ -0,0 +1,201 @@ |
| +// 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 android.graphics.Bitmap; |
| + |
| +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.ShortcutHelper; |
| +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 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) { |
| + mTab = tab; |
| + tab.addObserver(this); |
| + mWebappInfo = info; |
| + mNativePointer = nativeInitialize(mTab.getWebContents()); |
| + } |
| + |
| + /** |
| + * Updates the status of the native ManifestUpgradeDetector to start the web manifest resources |
| + * fetching pipeline. |
| + */ |
| + public void start() { |
| + nativeStart(mNativePointer); |
| + } |
| + |
| + /** |
| + * Puts the object in a state where it is safe to be destroyed. |
| + */ |
| + public void destroy() { |
| + 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, |
| + Bitmap icon, |
| + String[] iconUrls, int displayMode, int orientation, long themeColor, |
| + long backgroundColor) { |
| + final WebappInfo newInfo = WebappInfo.create(mWebappInfo.id(), startUrl, |
| + ShortcutHelper.encodeBitmapAsString(icon), name, shortName, |
| + displayMode, orientation, mWebappInfo.source(), themeColor, backgroundColor, |
| + false, mWebappInfo.webApkPackageName()); |
| + final Set<String> iconUrlSet = new HashSet<String>(Arrays.asList(iconUrls)); |
|
pkotwicz
2016/07/12 01:23:48
This if() statement should be in its own function.
Xi Han
2016/07/12 20:53:41
Done.
|
| + if (!mWebappInfo.uri().toString().equals(startUrl) |
| + || !mWebappInfo.name().equals(newInfo.name()) |
| + || mWebappInfo.backgroundColor() != newInfo.backgroundColor()) { |
| + mWebappInfo = newInfo; |
| + notifyObserver(true, true, iconUrlSet); |
| + return; |
| + } |
|
pkotwicz
2016/07/12 01:23:48
Should we always call WebappDataStorage#updateFrom
Xi Han
2016/07/12 20:53:41
We could, yes, then we don't need to check all tho
|
| + WebappRegistry.getWebappDataStorage(ContextUtils.getApplicationContext(), mWebappInfo.id(), |
| + new WebappRegistry.FetchWebappDataStorageCallback() { |
| + @Override |
| + public void onWebappDataStorageRetrieved(WebappDataStorage storage) { |
| + onWebappDataRetrieved(storage, newInfo, iconUrlSet); |
| + } |
| + }); |
| + } |
| + |
| + /** |
| + * Checks whether the new fetched resources match the ones stored in the SharedPreference. |
| + */ |
| + private void onWebappDataRetrieved(WebappDataStorage storage, WebappInfo newInfo, |
| + Set<String> iconUrlSet) { |
| + boolean isUpgraded = false; |
| + boolean updateSharedPreference = false; |
| + |
| + Set<String> cachedIconUrlsSet = storage.getIconUrls(); |
| + boolean isIconSame = checkIcon(ShortcutHelper.decodeBitmapFromString( |
| + storage.getIcon()), newInfo.icon()); |
| + if (cachedIconUrlsSet == null) { |
| + // If icon urls haven't been cached, whether to re-mint WebAPK depends on |
| + // other resources, but will update the SharedPreference. |
| + notifyObserver(!isIconSame, true, iconUrlSet); |
| + return; |
| + } |
| + boolean isIconUrlSetSame = checkIconUrlSet(cachedIconUrlsSet, iconUrlSet); |
| + if (!isIconSame || !isIconUrlSetSame) { |
| + isUpgraded = true; |
| + } |
| + if (isUpgraded || !mWebappInfo.shortName().equals(newInfo.shortName()) |
| + || mWebappInfo.displayMode() != newInfo.displayMode() |
| + || mWebappInfo.orientation() != newInfo.orientation() |
| + || mWebappInfo.themeColor() != newInfo.themeColor()) { |
| + updateSharedPreference = true; |
| + } |
| + if (isUpgraded || updateSharedPreference) { |
| + mWebappInfo = newInfo; |
| + } |
| + notifyObserver(isUpgraded, updateSharedPreference, iconUrlSet); |
| + } |
| + |
| + /** |
| + * 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); |
| + } |
| + |
| + /** |
| + * Returns whether two icons are the same. |
| + */ |
| + private boolean checkIcon(Bitmap icon, Bitmap anotherIcon) { |
| + if (icon == null) return anotherIcon == null; |
| + return icon.sameAs(anotherIcon); |
| + } |
| + |
| + private void notifyObserver(boolean isUpgraded, boolean updateSharedPreference, |
| + Set<String> iconUrls) { |
| + mObserver.onManifestAvaliable(isUpgraded, !isUpgraded && !updateSharedPreference ? null |
| + : mWebappInfo, iconUrls); |
| + } |
| + |
| + private native long nativeInitialize(WebContents webContents); |
| + private native void nativeReplaceWebContents(long nativeManifestUpgradeDetector, |
| + WebContents webContents); |
| + private native void nativeDestroy(long nativeManifestUpgradeDetector); |
| + private native void nativeStart(long nativeManifestUpgradeDetector); |
| +} |