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..2757bbc491d5d42b410d0ab54eebb3678df1b49d 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 |
@@ -9,9 +9,11 @@ import android.content.SharedPreferences; |
import android.os.SystemClock; |
import android.util.Log; |
+import org.chromium.base.ContextUtils; |
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,7 +22,11 @@ import java.util.Set; |
import java.util.concurrent.TimeUnit; |
/** |
- * Manages a rotating LRU buffer of WebappActivities to assign webapps to. |
+ * Before Lollipop, the only way to create multiple retargetable instances of the same Activity |
+ * was to explicitly define them in the Manifest. Given that the user can potentially have an |
+ * unlimited number of shortcuts for launching these Activities, we have to actively assign |
+ * shortcuts when they launch. Activities are reused in order of when they were last used, with |
+ * the least recently used ones reassigned first. |
* |
* 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. |
@@ -63,24 +69,38 @@ 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", |
+ "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_TYPE_COUNT = 2; |
- private static ActivityAssigner sInstance; |
+ private static final Object LOCK = new Object(); |
+ private static List<ActivityAssigner> sInstances; |
private final Context mContext; |
private final List<ActivityEntry> mActivityList; |
+ // The type index of the Activities managed. Either {@link WEBAPP_ACTIVITY_INDEX} or |
+ // {@link WEBAPK_ACTIVITY_INDEX}. |
+ private final int mActivityTypeIndex; |
/** |
* 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_TYPE_COUNT; ++i) { |
+ context.getSharedPreferences(PREF_PACKAGE[i], Context.MODE_PRIVATE); |
+ } |
} |
static class ActivityEntry { |
@@ -95,26 +115,32 @@ public class ActivityAssigner { |
/** |
* Returns the singleton instance, creating it if necessary. |
+ * @param webappId The app ID. |
*/ |
- public static ActivityAssigner instance(Context context) { |
+ public static ActivityAssigner instance(String webappId) { |
ThreadUtils.assertOnUiThread(); |
- if (sInstance == null) { |
- sInstance = new ActivityAssigner(context); |
+ synchronized (LOCK) { |
+ if (sInstances == null) { |
+ sInstances = new ArrayList<ActivityAssigner>(ACTIVITY_TYPE_COUNT); |
+ for (int i = 0; i < ACTIVITY_TYPE_COUNT; ++i) { |
+ sInstances.add(new ActivityAssigner(i)); |
+ } |
+ } |
} |
- return sInstance; |
+ return sInstances.get(ActivityAssigner.getIndex(webappId)); |
} |
- private ActivityAssigner(Context context) { |
- mContext = context.getApplicationContext(); |
+ private ActivityAssigner(int activityTypeIndex) { |
+ mContext = ContextUtils.getApplicationContext(); |
+ mActivityTypeIndex = activityTypeIndex; |
mActivityList = new ArrayList<ActivityEntry>(); |
- |
restoreActivityList(); |
} |
/** |
- * Assigns the webapp with the given ID to one of the available WebappActivities. |
- * If we know that the webapp was previously launched in one of the Activities, re-use it. |
- * Otherwise, take the least recently used WebappActivity ID and use that. |
+ * Assigns the app with the given ID to one of the available Activity instances. |
+ * If we know that the app was previously launched in one of the Activities, re-use it. |
+ * Otherwise, take the least recently used ID and use that. |
* @param webappId ID of the webapp. |
* @return Index of the Activity to use for the webapp. |
*/ |
@@ -134,6 +160,15 @@ public class ActivityAssigner { |
} |
/** |
+ * Returns {@link WEBAPP_ACTIVITY_INDEX} for WebappActivity, {@link WEBAPK_ACTIVITY_INDEX} for |
+ * WebApkActivity whose webappId starts with "webapk:". |
+ */ |
+ static 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. |
@@ -153,10 +188,10 @@ public class ActivityAssigner { |
} |
/** |
- * 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 an Activity to the back of the queue, indicating that the app is still in use and |
+ * shouldn't be killed. |
+ * @param activityIndex Index of the Activity in the LRU buffer. |
+ * @param webappId The ID of the app being shown in the Activity. |
*/ |
void markActivityUsed(int activityIndex, String webappId) { |
// Find the entry corresponding to the Activity. |
@@ -167,7 +202,7 @@ public class ActivityAssigner { |
return; |
} |
- // We have to reassign the webapp ID in case WebappActivities get repurposed. |
+ // We have to reassign the app ID in case Activities get repurposed. |
ActivityEntry updatedEntry = new ActivityEntry(activityIndex, webappId); |
mActivityList.remove(elementIndex); |
mActivityList.add(updatedEntry); |
@@ -189,7 +224,7 @@ public class ActivityAssigner { |
} |
/** |
- * Returns the current mapping between Activities and webapps. |
+ * Returns the current mapping between Activities and apps. |
*/ |
@VisibleForTesting |
List<ActivityEntry> getEntries() { |
@@ -197,9 +232,17 @@ public class ActivityAssigner { |
} |
/** |
- * Restores/creates the mapping between webapps and WebappActivities. |
+ * Returns the type index of the Activities managed. |
+ */ |
+ @VisibleForTesting |
+ int getActivityTypeIndex() { |
+ return mActivityTypeIndex; |
+ } |
+ |
+ /** |
+ * Restores/creates the mapping between apps and activities. |
* The logic is slightly complicated to future-proof against situations where the number of |
- * WebappActivities is changed. |
+ * Activity is changed. |
*/ |
private void restoreActivityList() { |
boolean isMapDirty = false; |
@@ -215,10 +258,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[mActivityTypeIndex], |
+ 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[mActivityTypeIndex], 0); |
try { |
RecordHistogram.recordTimesHistogram("Android.StrictMode.WebappSharedPrefs", |
SystemClock.elapsedRealtime() - time, TimeUnit.MILLISECONDS); |
@@ -227,8 +271,8 @@ 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[mActivityTypeIndex] + i; |
+ String currentWebappIdPref = PREF_WEBAPP_ID[mActivityTypeIndex] + i; |
int activityIndex = prefs.getInt(currentActivityIndexPref, i); |
String webappId = prefs.getString(currentWebappIdPref, null); |
@@ -253,7 +297,7 @@ public class ActivityAssigner { |
} |
} |
- // Add entries for any missing WebappActivities. |
+ // Add entries for any missing Activities. |
for (Integer availableIndex : availableWebapps) { |
ActivityEntry entry = new ActivityEntry(availableIndex, null); |
mActivityList.add(entry); |
@@ -266,16 +310,17 @@ public class ActivityAssigner { |
} |
/** |
- * Saves the mapping between webapps and WebappActivities. |
+ * Saves the mapping between apps and Activities. |
*/ |
private void storeActivityList() { |
- SharedPreferences prefs = mContext.getSharedPreferences(PREF_PACKAGE, Context.MODE_PRIVATE); |
+ SharedPreferences prefs = mContext.getSharedPreferences(PREF_PACKAGE[mActivityTypeIndex], |
+ Context.MODE_PRIVATE); |
SharedPreferences.Editor editor = prefs.edit(); |
editor.clear(); |
- editor.putInt(PREF_NUM_SAVED_ENTRIES, mActivityList.size()); |
+ editor.putInt(PREF_NUM_SAVED_ENTRIES[mActivityTypeIndex], mActivityList.size()); |
for (int i = 0; i < mActivityList.size(); ++i) { |
- String currentActivityIndexPref = PREF_ACTIVITY_INDEX + i; |
- String currentWebappIdPref = PREF_WEBAPP_ID + i; |
+ String currentActivityIndexPref = PREF_ACTIVITY_INDEX[mActivityTypeIndex] + i; |
+ String currentWebappIdPref = PREF_WEBAPP_ID[mActivityTypeIndex] + i; |
editor.putInt(currentActivityIndexPref, mActivityList.get(i).mActivityIndex); |
editor.putString(currentWebappIdPref, mActivityList.get(i).mWebappId); |
} |