Chromium Code Reviews| Index: chrome/android/java/src/org/chromium/chrome/browser/webapps/ActivityAssigner.java |
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/ActivityAssigner.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ActivityAssigner.java |
| index c01923984a7ed61d439d20aa2a7c4520ad5416ea..9ae5dcb543ad7b802e05dcf7b6af4c7d2efb84d9 100644 |
| --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/ActivityAssigner.java |
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ActivityAssigner.java |
| @@ -12,6 +12,7 @@ import android.util.Log; |
| import org.chromium.base.ThreadUtils; |
| import org.chromium.base.VisibleForTesting; |
| import org.chromium.base.metrics.RecordHistogram; |
| +import org.chromium.webapk.lib.common.WebApkConstants; |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| @@ -20,18 +21,21 @@ import java.util.Set; |
| import java.util.concurrent.TimeUnit; |
| /** |
| - * Manages a rotating LRU buffer of WebappActivities to assign webapps to. |
| + * Manages two rotating LRU buffers, one for WebappActivities, and the other one for |
| + * WebApkActivities to assign webapps to. |
| * |
|
gone
2016/05/25 21:50:14
Don't need to / everything, especially since you l
|
| - * In order to accommodate a limited number of WebappActivities with a potentially unlimited number |
| - * of webapps, we have to rotate the available WebappActivities between the webapps we start up. |
| + * In order to accommodate a limited number of WebappActivitiess/WebApkActivities with a |
| + * potentially unlimited number of webapps, we have to rotate the available |
| + * WebappActivities/WebApkActivities between the webapps we start up. |
| * Activities are reused in order of when they were last used, with the least recently used |
| * ones culled first. |
| * |
| * It is impossible to know whether Tasks have been removed from the Recent Task list without the |
| * GET_TASKS permission. As a result, the list of Activities inside the Recent Task list will |
| * be highly unlikely to match the list maintained in memory. Instead, we store the mapping as it |
| - * was the last time we changed it, which allows us to launch webapps in the WebappActivity they |
| - * were most recently associated with in cases where a user restarts a webapp from the Recent Tasks. |
| + * was the last time we changed it, which allows us to launch webapps in the |
| + * WebappActivity/WebApkActivity they were most recently associated with in cases where a user |
| + * restarts a webapp from the Recent Tasks. |
| * Note that in situations where the user manually clears the app data, we will again have an |
| * incorrect mapping. |
| * |
| @@ -63,24 +67,34 @@ public class ActivityAssigner { |
| // Don't ever change the package. Left for backwards compatibility. |
| @VisibleForTesting |
| - static final String PREF_PACKAGE = "com.google.android.apps.chrome.webapps"; |
| - static final String PREF_NUM_SAVED_ENTRIES = "ActivityAssigner.numSavedEntries"; |
| - static final String PREF_ACTIVITY_INDEX = "ActivityAssigner.activityIndex"; |
| - static final String PREF_WEBAPP_ID = "ActivityAssigner.webappId"; |
| + static final String PREF_PACKAGE[] = {"com.google.android.apps.chrome.webapps", |
|
gone
2016/05/25 21:50:13
Don't bother with adding another package -- just u
|
| + "com.google.android.apps.chrome.webapps.webapk"}; |
| + |
| + static final String PREF_NUM_SAVED_ENTRIES[] = {"ActivityAssigner.numSavedEntries", |
| + "ActivityAssigner.numSavedEntries.webapk"}; |
| + static final String PREF_ACTIVITY_INDEX[] = {"ActivityAssigner.activityIndex", |
| + "ActivityAssigner.activityIndex.webapk"}; |
| + static final String PREF_WEBAPP_ID[] = {"ActivityAssigner.webappId", |
| + "ActivityAssigner.webappId.webapk"}; |
| static final int INVALID_ACTIVITY_INDEX = -1; |
| + static final int WEBAPP_ACTIVITY_INDEX = 0; |
| + static final int WEBAPK_ACTIVITY_INDEX = 1; |
| + static final int ACTIVITY_TYPES = 2; |
|
gone
2016/05/25 21:50:14
nit: ACTIVITY_TYPE_COUNT
|
| private static ActivityAssigner sInstance; |
| private final Context mContext; |
| - private final List<ActivityEntry> mActivityList; |
| + private final List<ActivityEntry>[] mActivityList; |
| /** |
| * Pre-load shared prefs to avoid being blocked on the |
| * disk access async task in the future. |
| */ |
| public static void warmUpSharedPrefs(Context context) { |
| - context.getSharedPreferences(PREF_PACKAGE, Context.MODE_PRIVATE); |
| + for (int i = 0; i < ACTIVITY_TYPES; ++i) { |
| + context.getSharedPreferences(PREF_PACKAGE[i], Context.MODE_PRIVATE); |
| + } |
| } |
| static class ActivityEntry { |
| @@ -106,15 +120,18 @@ public class ActivityAssigner { |
| private ActivityAssigner(Context context) { |
| mContext = context.getApplicationContext(); |
| - mActivityList = new ArrayList<ActivityEntry>(); |
| - |
| - restoreActivityList(); |
| + mActivityList = new ArrayList[ACTIVITY_TYPES]; |
| + for (int i = 0; i < mActivityList.length; i++) { |
| + mActivityList[i] = new ArrayList<ActivityEntry>(); |
| + restoreActivityList(i); |
| + } |
| } |
| /** |
| - * Assigns the webapp with the given ID to one of the available WebappActivities. |
| + * Assigns the webapp with the given ID to one of the available |
| + * WebappActivities/WebApkActivities. |
|
gone
2016/05/25 21:50:13
Assign the app with the given ID to one of the ava
|
| * If we know that the webapp was previously launched in one of the Activities, re-use it. |
|
gone
2016/05/25 21:50:13
webapp -> app
least recently used ID and use that
|
| - * Otherwise, take the least recently used WebappActivity ID and use that. |
| + * Otherwise, take the least recently used WebappActivity/WebApkActivity ID and use that. |
| * @param webappId ID of the webapp. |
| * @return Index of the Activity to use for the webapp. |
| */ |
| @@ -124,9 +141,11 @@ public class ActivityAssigner { |
| // Allocate the one in the front of the list. |
| if (activityIndex == INVALID_ACTIVITY_INDEX) { |
| - activityIndex = mActivityList.get(0).mActivityIndex; |
| + // Get index of the LRU buffer depending on the {@link webappId}. |
| + int index = getIndex(webappId); |
| + activityIndex = mActivityList[index].get(0).mActivityIndex; |
| ActivityEntry newEntry = new ActivityEntry(activityIndex, webappId); |
| - mActivityList.set(0, newEntry); |
| + mActivityList[index].set(0, newEntry); |
| } |
| markActivityUsed(activityIndex, webappId); |
| @@ -134,6 +153,15 @@ public class ActivityAssigner { |
| } |
| /** |
| + * Returns {@link WEBAPP_ACTIVITY_INDEX} for WebappActivity, {@link WEBAPK_ACTIVITY_INDEX} for |
| + * WebApkActivity whose webappId starts with "webapk:". |
| + */ |
| + int getIndex(String webappId) { |
| + return webappId.startsWith(WebApkConstants.WEBAPK_ID_PREFIX) ? WEBAPK_ACTIVITY_INDEX |
| + : WEBAPP_ACTIVITY_INDEX; |
| + } |
| + |
| + /** |
| * Checks if the webapp with the given ID has been assigned to an Activity already. |
| * @param webappId ID of the webapp being displayed. |
| * @return Index of the Activity for the webapp if assigned, INVALID_ACTIVITY_INDEX otherwise. |
| @@ -144,23 +172,25 @@ public class ActivityAssigner { |
| } |
| // Go backwards in the queue to catch more recent instances of any duplicated webapps. |
| - for (int i = mActivityList.size() - 1; i >= 0; i--) { |
| - if (webappId.equals(mActivityList.get(i).mWebappId)) { |
| - return mActivityList.get(i).mActivityIndex; |
| + int index = getIndex(webappId); |
| + for (int i = mActivityList[index].size() - 1; i >= 0; i--) { |
| + if (webappId.equals(mActivityList[index].get(i).mWebappId)) { |
| + return mActivityList[index].get(i).mActivityIndex; |
| } |
| } |
| return INVALID_ACTIVITY_INDEX; |
| } |
| /** |
| - * Moves a WebappActivity to the back of the queue, indicating that the Webapp is still in use |
| - * and shouldn't be killed. |
| - * @param activityIndex Index of the WebappActivity. |
| - * @param webappId ID of the webapp being shown in the WebappActivity. |
| + * Moves a WebappActivity/WebApkActivity to the back of the queue, indicating that the Webapp |
| + * is still in use and shouldn't be killed. |
| + * @param activityIndex Index of the WebappActivity/WebApkActivity. |
| + * @param webappId ID of the webapp being shown in the WebappActivity/WebApkActivity. |
| */ |
| void markActivityUsed(int activityIndex, String webappId) { |
| // Find the entry corresponding to the Activity. |
| - int elementIndex = findActivityElement(activityIndex); |
| + int index = getIndex(webappId); |
| + int elementIndex = findActivityElement(activityIndex, index); |
| if (elementIndex == -1) { |
| Log.e(TAG, "Failed to find WebappActivity entry: " + activityIndex + ", " + webappId); |
| @@ -169,19 +199,20 @@ public class ActivityAssigner { |
| // We have to reassign the webapp ID in case WebappActivities get repurposed. |
| ActivityEntry updatedEntry = new ActivityEntry(activityIndex, webappId); |
| - mActivityList.remove(elementIndex); |
| - mActivityList.add(updatedEntry); |
| - storeActivityList(); |
| + mActivityList[index].remove(elementIndex); |
| + mActivityList[index].add(updatedEntry); |
| + storeActivityList(index); |
| } |
| /** |
| * Finds the index of the ActivityElement corresponding to the given activityIndex. |
| * @param activityIndex Index of the activity to find. |
| + * @param typeIndex Index of WebappActivities or WebApkActivities in {@link mActivityIndex}. |
| * @return The index of the ActivityElement in the activity list, or -1 if it couldn't be found. |
| */ |
| - private int findActivityElement(int activityIndex) { |
| - for (int elementIndex = 0; elementIndex < mActivityList.size(); elementIndex++) { |
| - if (mActivityList.get(elementIndex).mActivityIndex == activityIndex) { |
| + private int findActivityElement(int activityIndex, int typeIndex) { |
| + for (int elementIndex = 0; elementIndex < mActivityList[typeIndex].size(); elementIndex++) { |
| + if (mActivityList[typeIndex].get(elementIndex).mActivityIndex == activityIndex) { |
| return elementIndex; |
| } |
| } |
| @@ -192,18 +223,19 @@ public class ActivityAssigner { |
| * Returns the current mapping between Activities and webapps. |
| */ |
| @VisibleForTesting |
| - List<ActivityEntry> getEntries() { |
| + List<ActivityEntry>[] getEntries() { |
| return mActivityList; |
| } |
| /** |
| - * Restores/creates the mapping between webapps and WebappActivities. |
| + * Restores/creates the mapping between webapps and WebappActivities/WebApkActivities depending |
| + * on the {@link index}. |
| * The logic is slightly complicated to future-proof against situations where the number of |
| - * WebappActivities is changed. |
| + * WebappActivities/WebApkActivity is changed. |
| */ |
| - private void restoreActivityList() { |
| + private void restoreActivityList(int index) { |
| boolean isMapDirty = false; |
| - mActivityList.clear(); |
| + mActivityList[index].clear(); |
| // Create a Set of indices corresponding to every possible Activity. |
| // As ActivityEntries are read, they are and removed from this list to indicate that the |
| @@ -215,10 +247,11 @@ public class ActivityAssigner { |
| // Restore any entries that were previously saved. If it seems that the preferences have |
| // been corrupted somehow, just discard the whole map. |
| - SharedPreferences prefs = mContext.getSharedPreferences(PREF_PACKAGE, Context.MODE_PRIVATE); |
| + SharedPreferences prefs = mContext.getSharedPreferences(PREF_PACKAGE[index], |
| + Context.MODE_PRIVATE); |
| try { |
| long time = SystemClock.elapsedRealtime(); |
| - final int numSavedEntries = prefs.getInt(PREF_NUM_SAVED_ENTRIES, 0); |
| + final int numSavedEntries = prefs.getInt(PREF_NUM_SAVED_ENTRIES[index], 0); |
| try { |
| RecordHistogram.recordTimesHistogram("Android.StrictMode.WebappSharedPrefs", |
| SystemClock.elapsedRealtime() - time, TimeUnit.MILLISECONDS); |
| @@ -227,15 +260,15 @@ public class ActivityAssigner { |
| } |
| if (numSavedEntries <= NUM_WEBAPP_ACTIVITIES) { |
| for (int i = 0; i < numSavedEntries; ++i) { |
| - String currentActivityIndexPref = PREF_ACTIVITY_INDEX + i; |
| - String currentWebappIdPref = PREF_WEBAPP_ID + i; |
| + String currentActivityIndexPref = PREF_ACTIVITY_INDEX[index] + i; |
| + String currentWebappIdPref = PREF_WEBAPP_ID[index] + i; |
| int activityIndex = prefs.getInt(currentActivityIndexPref, i); |
| String webappId = prefs.getString(currentWebappIdPref, null); |
| ActivityEntry entry = new ActivityEntry(activityIndex, webappId); |
| if (availableWebapps.remove(entry.mActivityIndex)) { |
| - mActivityList.add(entry); |
| + mActivityList[index].add(entry); |
| } else { |
| // If the same activity was assigned to two different entries, or if the |
| // number of activities changed, discard it and mark that it needs to be |
| @@ -246,38 +279,40 @@ public class ActivityAssigner { |
| } |
| } catch (ClassCastException exception) { |
| // Something went wrong reading the preferences. Nuke everything. |
| - mActivityList.clear(); |
| + mActivityList[index].clear(); |
| availableWebapps.clear(); |
| for (int i = 0; i < NUM_WEBAPP_ACTIVITIES; ++i) { |
| availableWebapps.add(i); |
| } |
| } |
| - // Add entries for any missing WebappActivities. |
| + // Add entries for any missing WebappActivities/WebApkActivities. |
| for (Integer availableIndex : availableWebapps) { |
| ActivityEntry entry = new ActivityEntry(availableIndex, null); |
| - mActivityList.add(entry); |
| + mActivityList[index].add(entry); |
| isMapDirty = true; |
| } |
| if (isMapDirty) { |
| - storeActivityList(); |
| + storeActivityList(index); |
| } |
| } |
| /** |
| - * Saves the mapping between webapps and WebappActivities. |
| + * Saves the mapping between webapps and WebappActivities/WebApkActivities depending on the |
| + * {@link index}. |
| */ |
| - private void storeActivityList() { |
| - SharedPreferences prefs = mContext.getSharedPreferences(PREF_PACKAGE, Context.MODE_PRIVATE); |
| + private void storeActivityList(int index) { |
| + SharedPreferences prefs = mContext.getSharedPreferences(PREF_PACKAGE[index], |
| + Context.MODE_PRIVATE); |
| SharedPreferences.Editor editor = prefs.edit(); |
| editor.clear(); |
| - editor.putInt(PREF_NUM_SAVED_ENTRIES, mActivityList.size()); |
| - for (int i = 0; i < mActivityList.size(); ++i) { |
| - String currentActivityIndexPref = PREF_ACTIVITY_INDEX + i; |
| - String currentWebappIdPref = PREF_WEBAPP_ID + i; |
| - editor.putInt(currentActivityIndexPref, mActivityList.get(i).mActivityIndex); |
| - editor.putString(currentWebappIdPref, mActivityList.get(i).mWebappId); |
| + editor.putInt(PREF_NUM_SAVED_ENTRIES[index], mActivityList[index].size()); |
| + for (int i = 0; i < mActivityList[index].size(); ++i) { |
| + String currentActivityIndexPref = PREF_ACTIVITY_INDEX[index] + i; |
| + String currentWebappIdPref = PREF_WEBAPP_ID[index] + i; |
| + editor.putInt(currentActivityIndexPref, mActivityList[index].get(i).mActivityIndex); |
| + editor.putString(currentWebappIdPref, mActivityList[index].get(i).mWebappId); |
| } |
| editor.apply(); |
| } |