OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.chrome.browser.webapps; | 5 package org.chromium.chrome.browser.webapps; |
6 | 6 |
7 import android.content.Context; | 7 import android.content.Context; |
8 import android.content.Intent; | 8 import android.content.Intent; |
9 import android.content.SharedPreferences; | 9 import android.content.SharedPreferences; |
10 import android.graphics.Bitmap; | 10 import android.graphics.Bitmap; |
11 import android.os.AsyncTask; | 11 import android.os.AsyncTask; |
12 | 12 |
13 import org.chromium.base.ThreadUtils; | 13 import org.chromium.base.ThreadUtils; |
14 import org.chromium.base.VisibleForTesting; | 14 import org.chromium.base.VisibleForTesting; |
15 import org.chromium.chrome.browser.ShortcutHelper; | 15 import org.chromium.chrome.browser.ShortcutHelper; |
16 import org.chromium.chrome.browser.ShortcutSource; | 16 import org.chromium.chrome.browser.ShortcutSource; |
17 import org.chromium.chrome.browser.util.IntentUtils; | 17 import org.chromium.chrome.browser.util.IntentUtils; |
18 import org.chromium.content_public.common.ScreenOrientationValues; | 18 import org.chromium.content_public.common.ScreenOrientationValues; |
19 | 19 |
20 import java.util.Map; | 20 import java.util.Map; |
| 21 import java.util.concurrent.TimeUnit; |
21 | 22 |
22 /** | 23 /** |
23 * Stores data about an installed web app. Uses SharedPreferences to persist the
data to disk. | 24 * Stores data about an installed web app. Uses SharedPreferences to persist the
data to disk. |
24 * This class must only be accessed via {@link WebappRegistry}, which is used to
register and keep | 25 * This class must only be accessed via {@link WebappRegistry}, which is used to
register and keep |
25 * track of web app data known to Chrome. | 26 * track of web app data known to Chrome. |
26 */ | 27 */ |
27 public class WebappDataStorage { | 28 public class WebappDataStorage { |
28 | 29 |
29 static final String SHARED_PREFS_FILE_PREFIX = "webapp_"; | 30 static final String SHARED_PREFS_FILE_PREFIX = "webapp_"; |
30 static final String KEY_SPLASH_ICON = "splash_icon"; | 31 static final String KEY_SPLASH_ICON = "splash_icon"; |
31 static final String KEY_LAST_USED = "last_used"; | 32 static final String KEY_LAST_USED = "last_used"; |
32 static final String KEY_URL = "url"; | 33 static final String KEY_URL = "url"; |
33 static final String KEY_SCOPE = "scope"; | 34 static final String KEY_SCOPE = "scope"; |
34 static final String KEY_ICON = "icon"; | 35 static final String KEY_ICON = "icon"; |
35 static final String KEY_NAME = "name"; | 36 static final String KEY_NAME = "name"; |
36 static final String KEY_SHORT_NAME = "short_name"; | 37 static final String KEY_SHORT_NAME = "short_name"; |
37 static final String KEY_ORIENTATION = "orientation"; | 38 static final String KEY_ORIENTATION = "orientation"; |
38 static final String KEY_THEME_COLOR = "theme_color"; | 39 static final String KEY_THEME_COLOR = "theme_color"; |
39 static final String KEY_BACKGROUND_COLOR = "background_color"; | 40 static final String KEY_BACKGROUND_COLOR = "background_color"; |
40 static final String KEY_SOURCE = "source"; | 41 static final String KEY_SOURCE = "source"; |
41 static final String KEY_ACTION = "action"; | 42 static final String KEY_ACTION = "action"; |
42 static final String KEY_IS_ICON_GENERATED = "is_icon_generated"; | 43 static final String KEY_IS_ICON_GENERATED = "is_icon_generated"; |
43 static final String KEY_VERSION = "version"; | 44 static final String KEY_VERSION = "version"; |
| 45 static final String KEY_LAUNCHED = "launched"; |
44 | 46 |
45 // Unset/invalid constants for last used times and URLs. 0 is used as the nu
ll last | 47 // Unset/invalid constants for last used times and URLs. 0 is used as the nu
ll last |
46 // used time as WebappRegistry assumes that this is always a valid timestamp
. | 48 // used time as WebappRegistry assumes that this is always a valid timestamp
. |
47 static final long LAST_USED_UNSET = 0; | 49 static final long LAST_USED_UNSET = 0; |
48 static final long LAST_USED_INVALID = -1; | 50 static final long LAST_USED_INVALID = -1; |
49 static final String URL_INVALID = ""; | 51 static final String URL_INVALID = ""; |
50 static final int VERSION_INVALID = 0; | 52 static final int VERSION_INVALID = 0; |
51 | 53 |
| 54 // We use a heuristic to determine whether a web app is still installed on t
he home screen, as |
| 55 // there is no way to do so directly. Any web app which has been opened in t
he last ten days |
| 56 // is considered to be still on the home screen. |
| 57 static final long WEBAPP_LAST_OPEN_MAX_TIME = TimeUnit.DAYS.toMillis(10L); |
| 58 |
| 59 private static Clock sClock = new Clock(); |
52 private static Factory sFactory = new Factory(); | 60 private static Factory sFactory = new Factory(); |
53 | 61 |
54 private final String mId; | 62 private final String mId; |
55 private final SharedPreferences mPreferences; | 63 private final SharedPreferences mPreferences; |
56 | 64 |
57 /** | 65 /** |
58 * Opens an instance of WebappDataStorage for the web app specified. Must no
t be run on the UI | 66 * Opens an instance of WebappDataStorage for the web app specified. Must no
t be run on the UI |
59 * thread. | 67 * thread. |
60 * @param context The context to open the SharedPreferences. | 68 * @param context The context to open the SharedPreferences. |
61 * @param webappId The ID of the web app which is being opened. | 69 * @param webappId The ID of the web app which is being opened. |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
121 }.execute(); | 129 }.execute(); |
122 } | 130 } |
123 | 131 |
124 /** | 132 /** |
125 * Asynchronously retrieves the URL stored in this WebappDataStorage. Used i
n testing. | 133 * Asynchronously retrieves the URL stored in this WebappDataStorage. Used i
n testing. |
126 * @param context The context to read the SharedPreferences file. | 134 * @param context The context to read the SharedPreferences file. |
127 * @param webappId The ID of the web app the used time is being read for. | 135 * @param webappId The ID of the web app the used time is being read for. |
128 * @param callback Called when the URL has been retrieved. | 136 * @param callback Called when the URL has been retrieved. |
129 */ | 137 */ |
130 @VisibleForTesting | 138 @VisibleForTesting |
131 public static void getURL(final Context context, final String webappId, | 139 public static void getUrl(final Context context, final String webappId, |
132 final FetchCallback<String> callback) { | 140 final FetchCallback<String> callback) { |
133 new AsyncTask<Void, Void, String>() { | 141 new AsyncTask<Void, Void, String>() { |
134 @Override | 142 @Override |
135 protected final String doInBackground(Void... nothing) { | 143 protected final String doInBackground(Void... nothing) { |
136 return new WebappDataStorage(context.getApplicationContext(), we
bappId).getURL(); | 144 return new WebappDataStorage(context.getApplicationContext(), we
bappId).getUrl(); |
137 } | 145 } |
138 | 146 |
139 @Override | 147 @Override |
140 protected final void onPostExecute(String url) { | 148 protected final void onPostExecute(String url) { |
141 assert callback != null; | 149 assert callback != null; |
142 callback.onDataRetrieved(url); | 150 callback.onDataRetrieved(url); |
143 } | 151 } |
144 }.execute(); | 152 }.execute(); |
145 } | 153 } |
146 | 154 |
147 /** | 155 /** |
148 * Deletes the data for a web app by clearing all the information inside the
SharedPreferences | 156 * Deletes the data for a web app by clearing all the information inside the
SharedPreferences |
149 * file. This does NOT delete the file itself but the file is left empty. | 157 * file. This does NOT delete the file itself but the file is left empty. |
150 * @param context The context to read the SharedPreferences file. | 158 * @param context The context to read the SharedPreferences file. |
151 * @param webappId The ID of the web app being deleted. | 159 * @param webappId The ID of the web app being deleted. |
152 */ | 160 */ |
153 static void deleteDataForWebapp(final Context context, final String webappId
) { | 161 static void deleteDataForWebapp(final Context context, final String webappId
) { |
154 assert !ThreadUtils.runningOnUiThread(); | 162 assert !ThreadUtils.runningOnUiThread(); |
155 openSharedPreferences(context, webappId).edit().clear().apply(); | 163 openSharedPreferences(context, webappId).edit().clear().apply(); |
156 } | 164 } |
157 | 165 |
158 /** | 166 /** |
159 * Deletes the URL and scope, and sets last used time to 0 in SharedPreferen
ces. | 167 * Deletes the launched flag, URL and scope, and sets last used time to 0 in
SharedPreferences. |
160 * This does not remove the stored splash screen image (if any) for the app. | 168 * This does not remove the stored splash screen image (if any) for the app. |
161 * @param context The context to read the SharedPreferences file. | 169 * @param context The context to read the SharedPreferences file. |
162 * @param webappId The ID of the web app for which history is being cleared. | 170 * @param webappId The ID of the web app for which history is being cleared. |
163 */ | 171 */ |
164 static void clearHistory(final Context context, final String webappId) { | 172 static void clearHistory(final Context context, final String webappId) { |
| 173 assert !ThreadUtils.runningOnUiThread(); |
| 174 SharedPreferences.Editor editor = openSharedPreferences(context, webappI
d).edit(); |
| 175 |
165 // The last used time is set to 0 to ensure that a valid value is always
present. | 176 // The last used time is set to 0 to ensure that a valid value is always
present. |
166 // If the web app is not launched prior to the next cleanup, then its re
maining data will be | 177 // If the web app is not launched prior to the next cleanup, then its re
maining data will be |
167 // removed. Otherwise, the next launch will update the last used time. | 178 // removed. Otherwise, the next launch from home screen will update the
last used time. |
168 assert !ThreadUtils.runningOnUiThread(); | 179 editor.putLong(KEY_LAST_USED, LAST_USED_UNSET); |
169 openSharedPreferences(context, webappId).edit() | 180 editor.remove(KEY_LAUNCHED); |
170 .putLong(KEY_LAST_USED, LAST_USED_UNSET).remove(KEY_URL).remove(
KEY_SCOPE).apply(); | 181 editor.remove(KEY_URL); |
| 182 editor.remove(KEY_SCOPE); |
| 183 editor.apply(); |
171 } | 184 } |
172 | 185 |
173 /** | 186 /** |
| 187 * Sets the clock used to get the current time. |
| 188 */ |
| 189 @VisibleForTesting |
| 190 public static void setClockForTests(Clock clock) { |
| 191 sClock = clock; |
| 192 } |
| 193 |
| 194 /** |
174 * Sets the factory used to generate WebappDataStorage objects. | 195 * Sets the factory used to generate WebappDataStorage objects. |
175 */ | 196 */ |
176 @VisibleForTesting | 197 @VisibleForTesting |
177 public static void setFactoryForTests(Factory factory) { | 198 public static void setFactoryForTests(Factory factory) { |
178 sFactory = factory; | 199 sFactory = factory; |
179 } | 200 } |
180 | 201 |
181 private static SharedPreferences openSharedPreferences(Context context, Stri
ng webappId) { | 202 private static SharedPreferences openSharedPreferences(Context context, Stri
ng webappId) { |
182 return context.getApplicationContext().getSharedPreferences( | 203 return context.getApplicationContext().getSharedPreferences( |
183 SHARED_PREFS_FILE_PREFIX + webappId, Context.MODE_PRIVATE); | 204 SHARED_PREFS_FILE_PREFIX + webappId, Context.MODE_PRIVATE); |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
319 /** | 340 /** |
320 * Returns the scope stored in this object, or URL_INVALID if it is not stor
ed. | 341 * Returns the scope stored in this object, or URL_INVALID if it is not stor
ed. |
321 */ | 342 */ |
322 String getScope() { | 343 String getScope() { |
323 return mPreferences.getString(KEY_SCOPE, URL_INVALID); | 344 return mPreferences.getString(KEY_SCOPE, URL_INVALID); |
324 } | 345 } |
325 | 346 |
326 /** | 347 /** |
327 * Returns the URL stored in this object, or URL_INVALID if it is not stored
. | 348 * Returns the URL stored in this object, or URL_INVALID if it is not stored
. |
328 */ | 349 */ |
329 String getURL() { | 350 String getUrl() { |
330 return mPreferences.getString(KEY_URL, URL_INVALID); | 351 return mPreferences.getString(KEY_URL, URL_INVALID); |
331 } | 352 } |
332 | 353 |
333 /** | 354 /** |
334 * Updates the last used time of this object. | 355 * Updates the last used time of this object. |
335 * @param lastUsedTime the new last used time. | |
336 */ | 356 */ |
337 void updateLastUsedTime() { | 357 void updateLastUsedTime() { |
338 mPreferences.edit().putLong(KEY_LAST_USED, System.currentTimeMillis()).a
pply(); | 358 mPreferences.edit().putLong(KEY_LAST_USED, sClock.currentTimeMillis()).a
pply(); |
339 } | 359 } |
340 | 360 |
341 /** | 361 /** |
342 * Returns the last used time of this object, or -1 if it is not stored. | 362 * Returns the last used time of this object, or -1 if it is not stored. |
343 */ | 363 */ |
344 long getLastUsedTime() { | 364 long getLastUsedTime() { |
345 return mPreferences.getLong(KEY_LAST_USED, LAST_USED_INVALID); | 365 return mPreferences.getLong(KEY_LAST_USED, LAST_USED_INVALID); |
346 } | 366 } |
347 | 367 |
| 368 /** |
| 369 * Returns true if this web app has been launched from home screen recently
(within |
| 370 * WEBAPP_LAST_OPEN_MAX_TIME milliseconds). |
| 371 */ |
| 372 public boolean wasLaunchedRecently() { |
| 373 // Registering the web app sets the last used time, so we must also ensu
re that the web app |
| 374 // has actually been launched. Otherwise, launches from home screen are
the only occasion |
| 375 // when last used time is updated. |
| 376 return getLaunched() |
| 377 && (sClock.currentTimeMillis() - getLastUsedTime() < WEBAPP_LAST
_OPEN_MAX_TIME); |
| 378 } |
| 379 |
| 380 /** |
| 381 * Returns true if this web app has been launched from home screen. |
| 382 */ |
| 383 boolean getLaunched() { |
| 384 return mPreferences.getBoolean(KEY_LAUNCHED, false); |
| 385 } |
| 386 |
| 387 /** |
| 388 * Marks this web app as having been launched from home screen. |
| 389 */ |
| 390 void setLaunched() { |
| 391 mPreferences.edit().putBoolean(KEY_LAUNCHED, true).apply(); |
| 392 } |
| 393 |
348 private Map<String, ?> getAllData() { | 394 private Map<String, ?> getAllData() { |
349 return mPreferences.getAll(); | 395 return mPreferences.getAll(); |
350 } | 396 } |
351 | 397 |
352 /** | 398 /** |
353 * Called after data has been retrieved from storage. | 399 * Called after data has been retrieved from storage. |
354 */ | 400 */ |
355 public interface FetchCallback<T> { | 401 public interface FetchCallback<T> { |
356 public void onDataRetrieved(T readObject); | 402 public void onDataRetrieved(T readObject); |
357 } | 403 } |
358 | 404 |
359 /** | 405 /** |
360 * Factory used to generate WebappDataStorage objects. | 406 * Factory used to generate WebappDataStorage objects. |
361 * | 407 * |
362 * It is used in tests to override methods in WebappDataStorage and inject t
he mocked objects. | 408 * It is used in tests to override methods in WebappDataStorage and inject t
he mocked objects. |
363 */ | 409 */ |
364 public static class Factory { | 410 public static class Factory { |
365 | 411 |
366 /** | 412 /** |
367 * Generates a WebappDataStorage class for a specified web app. | 413 * Generates a WebappDataStorage class for a specified web app. |
368 */ | 414 */ |
369 public WebappDataStorage create(final Context context, final String weba
ppId) { | 415 public WebappDataStorage create(final Context context, final String weba
ppId) { |
370 return new WebappDataStorage(context, webappId); | 416 return new WebappDataStorage(context, webappId); |
371 } | 417 } |
372 } | 418 } |
| 419 |
| 420 /** |
| 421 * Clock used to generate the current time in millseconds for updating and s
etting last used |
| 422 * time. |
| 423 */ |
| 424 public static class Clock { |
| 425 /** |
| 426 * Returns the current time in milliseconds. |
| 427 */ |
| 428 public long currentTimeMillis() { |
| 429 return System.currentTimeMillis(); |
| 430 } |
| 431 } |
373 } | 432 } |
OLD | NEW |