Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(256)

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java

Issue 1845233002: Store standalone web app data in WebappDataStorage as well as the homescreen intent. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@notification-deep-linking
Patch Set: Improve comments Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java
index fabf9fb1324426f58f60bdc5ddafc3386f95350c..f202757cac331fbbb5a7c43782dbfbfccb79abde 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java
@@ -5,6 +5,7 @@
package org.chromium.chrome.browser.webapps;
import android.content.Context;
+import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.os.AsyncTask;
@@ -12,6 +13,9 @@ import android.os.AsyncTask;
import org.chromium.base.ThreadUtils;
import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.browser.ShortcutHelper;
+import org.chromium.chrome.browser.ShortcutSource;
+import org.chromium.chrome.browser.util.IntentUtils;
+import org.chromium.content_public.common.ScreenOrientationValues;
import java.util.Map;
@@ -31,16 +35,28 @@ public class WebappDataStorage {
static final String SHARED_PREFS_FILE_PREFIX = "webapp_";
static final String KEY_SPLASH_ICON = "splash_icon";
static final String KEY_LAST_USED = "last_used";
+ static final String KEY_URL = "url";
static final String KEY_SCOPE = "scope";
+ static final String KEY_ICON = "icon";
+ static final String KEY_NAME = "name";
+ static final String KEY_SHORT_NAME = "short_name";
+ static final String KEY_ORIENTATION = "orientation";
+ static final String KEY_THEME_COLOR = "theme_color";
+ static final String KEY_BACKGROUND_COLOR = "background_color";
+ static final String KEY_SOURCE = "source";
+ static final String KEY_ACTION = "action";
+ static final String KEY_IS_ICON_GENERATED = "is_icon_generated";
- // Unset/invalid constants for last used times and scopes. 0 is used as the null last
+ // Unset/invalid constants for last used times and URLs. 0 is used as the null last
// used time as WebappRegistry assumes that this is always a valid timestamp.
static final long LAST_USED_UNSET = 0;
static final long LAST_USED_INVALID = -1;
- static final String SCOPE_INVALID = "";
+ static final String URL_INVALID = "";
+ static final String NAME_INVALID = "";
private static Factory sFactory = new Factory();
+ private final String mId;
private final SharedPreferences mPreferences;
/**
@@ -48,7 +64,7 @@ public class WebappDataStorage {
* @param context The context to open the SharedPreferences.
* @param webappId The ID of the web app which is being opened.
*/
- public static WebappDataStorage open(final Context context, final String webappId) {
+ static WebappDataStorage open(final Context context, final String webappId) {
final WebappDataStorage storage = sFactory.create(context, webappId);
new AsyncTask<Void, Void, Void>() {
@Override
@@ -94,7 +110,7 @@ public class WebappDataStorage {
/**
* Asynchronously retrieves the scope stored in this WebappDataStorage. The scope is the URL
- * over which the webapp data is applied to.
+ * over which the web app data is applied to.
* @param context The context to read the SharedPreferences file.
* @param webappId The ID of the web app the used time is being read for.
* @param callback Called when the scope has been retrieved.
@@ -105,8 +121,7 @@ public class WebappDataStorage {
new AsyncTask<Void, Void, String>() {
@Override
protected final String doInBackground(Void... nothing) {
- return new WebappDataStorage(context.getApplicationContext(), webappId)
- .getScope();
+ return new WebappDataStorage(context.getApplicationContext(), webappId).getScope();
}
@Override
@@ -117,20 +132,23 @@ public class WebappDataStorage {
}
/**
- * Asynchronously sets the scope stored in this WebappDataStorage. Does nothing if there
- * is already a scope stored; since webapps added to homescreen cannot change the scope which
- * they launch, it is not intended that a WebappDataStorage will be able to change the scope
- * once it is set.
+ * Asynchronously retrieves the URL stored in this WebappDataStorage.
* @param context The context to read the SharedPreferences file.
* @param webappId The ID of the web app the used time is being read for.
- * @param scope The scope to set for the web app.
+ * @param callback Called when the URL has been retrieved.
*/
- public static void setScope(final Context context, final String webappId, final String scope) {
- new AsyncTask<Void, Void, Void>() {
+ @VisibleForTesting
+ public static void getURL(final Context context, final String webappId,
+ final FetchCallback<String> callback) {
+ new AsyncTask<Void, Void, String>() {
@Override
- protected final Void doInBackground(Void... nothing) {
- new WebappDataStorage(context.getApplicationContext(), webappId).setScope(scope);
- return null;
+ protected final String doInBackground(Void... nothing) {
+ return new WebappDataStorage(context.getApplicationContext(), webappId).getURL();
+ }
+
+ @Override
+ protected final void onPostExecute(String url) {
+ callback.onDataRetrieved(url);
}
}.execute();
}
@@ -147,18 +165,18 @@ public class WebappDataStorage {
}
/**
- * Deletes the scope and sets last used time to 0 this web app in SharedPreferences.
+ * Deletes the URL and scope, and sets last used time to 0 in SharedPreferences.
* This does not remove the stored splash screen image (if any) for the app.
* @param context The context to read the SharedPreferences file.
- * @param webappId The ID of the web app being deleted.
+ * @param webappId The ID of the web app for which history is being cleared.
*/
static void clearHistory(final Context context, final String webappId) {
// The last used time is set to 0 to ensure that a valid value is always present.
- // If the webapp is not launched prior to the next cleanup, then its remaining data will be
+ // If the web app is not launched prior to the next cleanup, then its remaining data will be
// removed. Otherwise, the next launch will update the last used time.
assert !ThreadUtils.runningOnUiThread();
- openSharedPreferences(context, webappId)
- .edit().putLong(KEY_LAST_USED, LAST_USED_UNSET).remove(KEY_SCOPE).apply();
+ openSharedPreferences(context, webappId).edit()
+ .putLong(KEY_LAST_USED, LAST_USED_UNSET).remove(KEY_URL).remove(KEY_SCOPE).apply();
}
/**
@@ -175,6 +193,7 @@ public class WebappDataStorage {
}
protected WebappDataStorage(Context context, String webappId) {
+ mId = webappId;
mPreferences = openSharedPreferences(context, webappId);
}
@@ -200,31 +219,80 @@ public class WebappDataStorage {
}
/*
- * Update the information associated with the web app with the specified data.
+ * Update the information associated with the web app with the specified data. Must not be
+ * called on the UI thread.
* @param splashScreenImage The image which should be shown on the splash screen of the web app.
*/
public void updateSplashScreenImage(final Bitmap splashScreenImage) {
+ assert !ThreadUtils.runningOnUiThread();
+ mPreferences.edit().putString(KEY_SPLASH_ICON,
+ ShortcutHelper.encodeBitmapAsString(splashScreenImage)).apply();
+ }
+
+ public void createWebappLaunchIntent(final FetchCallback<Intent> callback) {
gone 2016/04/01 23:44:48 AIUI no value in reading these preferences on a ba
dominickn 2016/04/04 07:26:24 This method has a possibly expensive bitmap unpack
gone 2016/04/04 19:04:02 Arg, missed that call in that blob. sgtm
+ new AsyncTask<Void, Void, Intent>() {
+ @Override
+ protected final Intent doInBackground(Void... nothing) {
+ // Assume that all of the data is invalid if the name is not set. Otherwise, assume
+ // that all of the data is valid.
+ String name = mPreferences.getString(KEY_NAME, NAME_INVALID);
+ if (name.equals(NAME_INVALID)) return null;
+
+ return ShortcutHelper.createWebappShortcutIntent(mId,
+ mPreferences.getString(KEY_ACTION, null),
+ mPreferences.getString(KEY_URL, null), name,
+ mPreferences.getString(KEY_SHORT_NAME, null),
+ ShortcutHelper.decodeBitmapFromString(
+ mPreferences.getString(KEY_ICON, null)),
+ mPreferences.getInt(KEY_ORIENTATION, ScreenOrientationValues.DEFAULT),
+ mPreferences.getLong(KEY_THEME_COLOR,
+ ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING),
+ mPreferences.getLong(KEY_BACKGROUND_COLOR,
+ ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING),
+ mPreferences.getBoolean(KEY_IS_ICON_GENERATED, false));
+ }
+
+ @Override
+ protected final void onPostExecute(Intent result) {
+ callback.onDataRetrieved(result);
+ }
+ }.execute();
+ }
+
+ /**
+ * Updates the data stored in this object to match that in the supplied intent. Calls the
+ * provided callback when the update is complete.
+ * @param intent the web app intent to update this object to match.
+ * @param callback the callback to run when the update is complete.
+ */
+ public void updateFromShortcutIntent(final Intent shortcutIntent, final Runnable callback) {
new AsyncTask<Void, Void, Void>() {
@Override
protected final Void doInBackground(Void... nothing) {
- mPreferences.edit()
- .putString(KEY_SPLASH_ICON,
- ShortcutHelper.encodeBitmapAsString(splashScreenImage))
- .apply();
+ updateFromIntent(shortcutIntent);
return null;
}
+
+ @Override
+ protected final void onPostExecute(Void nothing) {
+ assert callback != null;
+ callback.run();
+ }
}.execute();
}
/**
- * Updates the scope stored in this object. Does nothing if there is already a scope stored.
- * @param scope the scope to store.
+ * Updates the data stored in this object to match that in the supplied intent.
+ * @param intent the web app intent to update this object to match.
*/
- void setScope(String scope) {
- assert !ThreadUtils.runningOnUiThread();
- if (mPreferences.getString(KEY_SCOPE, SCOPE_INVALID).equals(SCOPE_INVALID)) {
- mPreferences.edit().putString(KEY_SCOPE, scope).apply();
- }
+ public void updateFromShortcutIntent(final Intent shortcutIntent) {
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected final Void doInBackground(Void... nothing) {
+ updateFromIntent(shortcutIntent);
+ return null;
+ }
+ }.execute();
}
/**
@@ -232,7 +300,72 @@ public class WebappDataStorage {
*/
String getScope() {
assert !ThreadUtils.runningOnUiThread();
- return mPreferences.getString(KEY_SCOPE, SCOPE_INVALID);
+ return mPreferences.getString(KEY_SCOPE, URL_INVALID);
+ }
+
+ /**
+ * Returns the URL stored in this object, or "" if it is not stored.
gone 2016/04/01 23:44:48 Should be more explicit bot here and in the previo
dominickn 2016/04/04 07:26:24 Done.
+ */
+ String getURL() {
+ assert !ThreadUtils.runningOnUiThread();
+ return mPreferences.getString(KEY_URL, URL_INVALID);
+ }
+
+ /**
+ * Updates this object from the fields in the suppled intent. Does not check if the intent is
gone 2016/04/01 23:44:48 nit: supplied
dominickn 2016/04/04 07:26:24 Done.
+ * a valid web app launch intent.
+ */
+ private void updateFromIntent(Intent shortcutIntent) {
+ assert !ThreadUtils.runningOnUiThread();
+ SharedPreferences.Editor editor = mPreferences.edit();
+ boolean updated = false;
+
+ // The URL and scope may have been deleted by the user clearing their history. Check whether
+ // they are present, and update if necessary.
+ String url = mPreferences.getString(KEY_URL, URL_INVALID);
+ if (url.equals(URL_INVALID)) {
+ url = IntentUtils.safeGetStringExtra(shortcutIntent, ShortcutHelper.EXTRA_URL);
+ editor.putString(KEY_URL, url);
+ updated = true;
+ }
+
+ if (mPreferences.getString(KEY_SCOPE, URL_INVALID).equals(URL_INVALID)) {
+ String scope = IntentUtils.safeGetStringExtra(
+ shortcutIntent, ShortcutHelper.EXTRA_SCOPE);
+ if (scope == null) scope = url;
+
+ editor.putString(KEY_SCOPE, scope);
+ updated = true;
+ }
+
+ // For all other fields, assume that if the name key is present, then all fields are
+ // present and do not need to be updated. All fields except for the last used time, scope,
+ // and URL are either set or cleared together.
gone 2016/04/01 23:44:48 Are we going to have to start worrying about versi
dominickn 2016/04/04 07:26:24 Yeah, versioning is probably a good idea. Done.
+ if (mPreferences.getString(KEY_NAME, NAME_INVALID).equals(NAME_INVALID)) {
+ editor.putString(KEY_ICON, IntentUtils.safeGetStringExtra(
+ shortcutIntent, ShortcutHelper.EXTRA_ICON));
+ editor.putInt(KEY_ORIENTATION, IntentUtils.safeGetIntExtra(
+ shortcutIntent, ShortcutHelper.EXTRA_ORIENTATION,
+ ScreenOrientationValues.DEFAULT));
+ editor.putLong(KEY_THEME_COLOR, IntentUtils.safeGetLongExtra(
+ shortcutIntent, ShortcutHelper.EXTRA_THEME_COLOR,
+ ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING));
+ editor.putLong(KEY_BACKGROUND_COLOR, IntentUtils.safeGetLongExtra(
+ shortcutIntent, ShortcutHelper.EXTRA_BACKGROUND_COLOR,
+ ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING));
+ editor.putInt(KEY_SOURCE, IntentUtils.safeGetIntExtra(
+ shortcutIntent, ShortcutHelper.EXTRA_SOURCE,
+ ShortcutSource.UNKNOWN));
+ editor.putString(KEY_NAME, IntentUtils.safeGetStringExtra(
+ shortcutIntent, ShortcutHelper.EXTRA_NAME));
+ editor.putString(KEY_SHORT_NAME, IntentUtils.safeGetStringExtra(
+ shortcutIntent, ShortcutHelper.EXTRA_SHORT_NAME));
+ editor.putBoolean(KEY_IS_ICON_GENERATED, IntentUtils.safeGetBooleanExtra(
+ shortcutIntent, ShortcutHelper.EXTRA_IS_ICON_GENERATED, false));
+ editor.putString(KEY_ACTION, shortcutIntent.getAction());
+ updated = true;
+ }
+ if (updated) editor.apply();
}
/**

Powered by Google App Engine
This is Rietveld 408576698