Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
michael@0 | 1 | /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- |
michael@0 | 2 | * This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | package org.mozilla.gecko.webapp; |
michael@0 | 7 | |
michael@0 | 8 | import java.util.ArrayList; |
michael@0 | 9 | |
michael@0 | 10 | import org.mozilla.gecko.GeckoAppShell; |
michael@0 | 11 | |
michael@0 | 12 | import android.content.Context; |
michael@0 | 13 | import android.content.SharedPreferences; |
michael@0 | 14 | import android.content.SharedPreferences.Editor; |
michael@0 | 15 | import android.util.Log; |
michael@0 | 16 | |
michael@0 | 17 | public class Allocator { |
michael@0 | 18 | |
michael@0 | 19 | private final String LOGTAG = "GeckoWebappAllocator"; |
michael@0 | 20 | |
michael@0 | 21 | private static final String PREFIX_ORIGIN = "webapp-origin-"; |
michael@0 | 22 | private static final String PREFIX_PACKAGE_NAME = "webapp-package-name-"; |
michael@0 | 23 | |
michael@0 | 24 | // These prefixes are for prefs used by the old shortcut-based runtime. |
michael@0 | 25 | // We define them here so maybeMigrateOldPrefs can migrate them to their |
michael@0 | 26 | // new equivalents if this app was originally installed as a shortcut. |
michael@0 | 27 | // Maybe we can remove this code in the future! |
michael@0 | 28 | private static final String PREFIX_OLD_APP = "app"; |
michael@0 | 29 | private static final String PREFIX_OLD_ICON = "icon"; |
michael@0 | 30 | |
michael@0 | 31 | // The number of Webapp# and WEBAPP# activities/apps/intents |
michael@0 | 32 | private final static int MAX_WEB_APPS = 100; |
michael@0 | 33 | |
michael@0 | 34 | protected static Allocator sInstance = null; |
michael@0 | 35 | public static Allocator getInstance() { |
michael@0 | 36 | return getInstance(GeckoAppShell.getContext()); |
michael@0 | 37 | } |
michael@0 | 38 | |
michael@0 | 39 | public static synchronized Allocator getInstance(Context cx) { |
michael@0 | 40 | if (sInstance == null) { |
michael@0 | 41 | sInstance = new Allocator(cx); |
michael@0 | 42 | } |
michael@0 | 43 | |
michael@0 | 44 | return sInstance; |
michael@0 | 45 | } |
michael@0 | 46 | |
michael@0 | 47 | SharedPreferences mPrefs; |
michael@0 | 48 | |
michael@0 | 49 | protected Allocator(Context context) { |
michael@0 | 50 | mPrefs = context.getSharedPreferences("webapps", Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS); |
michael@0 | 51 | } |
michael@0 | 52 | |
michael@0 | 53 | private static String appKey(int index) { |
michael@0 | 54 | return PREFIX_PACKAGE_NAME + index; |
michael@0 | 55 | } |
michael@0 | 56 | |
michael@0 | 57 | public static String iconKey(int index) { |
michael@0 | 58 | return "web-app-color-" + index; |
michael@0 | 59 | } |
michael@0 | 60 | |
michael@0 | 61 | public static String originKey(int i) { |
michael@0 | 62 | return PREFIX_ORIGIN + i; |
michael@0 | 63 | } |
michael@0 | 64 | |
michael@0 | 65 | private static String oldAppKey(int index) { |
michael@0 | 66 | return PREFIX_OLD_APP + index; |
michael@0 | 67 | } |
michael@0 | 68 | |
michael@0 | 69 | private static String oldIconKey(int index) { |
michael@0 | 70 | return PREFIX_OLD_ICON + index; |
michael@0 | 71 | } |
michael@0 | 72 | |
michael@0 | 73 | private static void save(Editor editor) { |
michael@0 | 74 | // Use SharedPreferences.Editor.apply() where available and commit() |
michael@0 | 75 | // where it isn't. We could also use a background thread with commit(), |
michael@0 | 76 | // but our callers might expect the changes we make to be available |
michael@0 | 77 | // immediately, so we instead take the commit() performance hit |
michael@0 | 78 | // on the small percentage of extant devices that don't support apply(). |
michael@0 | 79 | if (android.os.Build.VERSION.SDK_INT > 8) { |
michael@0 | 80 | editor.apply(); |
michael@0 | 81 | } else { |
michael@0 | 82 | editor.commit(); |
michael@0 | 83 | } |
michael@0 | 84 | } |
michael@0 | 85 | |
michael@0 | 86 | public ArrayList<String> getInstalledPackageNames() { |
michael@0 | 87 | ArrayList<String> installedPackages = new ArrayList<String>(); |
michael@0 | 88 | |
michael@0 | 89 | for (int i = 0; i < MAX_WEB_APPS; ++i) { |
michael@0 | 90 | if (mPrefs.contains(appKey(i))) { |
michael@0 | 91 | installedPackages.add(mPrefs.getString(appKey(i), "")); |
michael@0 | 92 | } |
michael@0 | 93 | } |
michael@0 | 94 | return installedPackages; |
michael@0 | 95 | } |
michael@0 | 96 | |
michael@0 | 97 | public synchronized int findOrAllocatePackage(final String packageName) { |
michael@0 | 98 | int index = getIndexForApp(packageName); |
michael@0 | 99 | if (index != -1) |
michael@0 | 100 | return index; |
michael@0 | 101 | |
michael@0 | 102 | for (int i = 0; i < MAX_WEB_APPS; ++i) { |
michael@0 | 103 | if (!mPrefs.contains(appKey(i))) { |
michael@0 | 104 | // found unused index i |
michael@0 | 105 | putPackageName(i, packageName); |
michael@0 | 106 | return i; |
michael@0 | 107 | } |
michael@0 | 108 | } |
michael@0 | 109 | |
michael@0 | 110 | // no more apps! |
michael@0 | 111 | return -1; |
michael@0 | 112 | } |
michael@0 | 113 | |
michael@0 | 114 | public synchronized void putPackageName(final int index, final String packageName) { |
michael@0 | 115 | save(mPrefs.edit().putString(appKey(index), packageName)); |
michael@0 | 116 | } |
michael@0 | 117 | |
michael@0 | 118 | public void updateColor(int index, int color) { |
michael@0 | 119 | save(mPrefs.edit().putInt(iconKey(index), color)); |
michael@0 | 120 | } |
michael@0 | 121 | |
michael@0 | 122 | public synchronized int getIndexForApp(String packageName) { |
michael@0 | 123 | return findSlotForPrefix(PREFIX_PACKAGE_NAME, packageName); |
michael@0 | 124 | } |
michael@0 | 125 | |
michael@0 | 126 | public synchronized int getIndexForOrigin(String origin) { |
michael@0 | 127 | return findSlotForPrefix(PREFIX_ORIGIN, origin); |
michael@0 | 128 | } |
michael@0 | 129 | |
michael@0 | 130 | protected int findSlotForPrefix(String prefix, String value) { |
michael@0 | 131 | for (int i = 0; i < MAX_WEB_APPS; ++i) { |
michael@0 | 132 | if (mPrefs.getString(prefix + i, "").equals(value)) { |
michael@0 | 133 | return i; |
michael@0 | 134 | } |
michael@0 | 135 | } |
michael@0 | 136 | return -1; |
michael@0 | 137 | } |
michael@0 | 138 | |
michael@0 | 139 | public synchronized String getAppForIndex(int index) { |
michael@0 | 140 | return mPrefs.getString(appKey(index), null); |
michael@0 | 141 | } |
michael@0 | 142 | |
michael@0 | 143 | public synchronized int releaseIndexForApp(String app) { |
michael@0 | 144 | int index = getIndexForApp(app); |
michael@0 | 145 | if (index == -1) |
michael@0 | 146 | return -1; |
michael@0 | 147 | |
michael@0 | 148 | releaseIndex(index); |
michael@0 | 149 | return index; |
michael@0 | 150 | } |
michael@0 | 151 | |
michael@0 | 152 | public synchronized void releaseIndex(final int index) { |
michael@0 | 153 | save(mPrefs.edit().remove(appKey(index)).remove(iconKey(index)).remove(originKey(index))); |
michael@0 | 154 | } |
michael@0 | 155 | |
michael@0 | 156 | public void putOrigin(int index, String origin) { |
michael@0 | 157 | save(mPrefs.edit().putString(originKey(index), origin)); |
michael@0 | 158 | } |
michael@0 | 159 | |
michael@0 | 160 | public String getOrigin(int index) { |
michael@0 | 161 | return mPrefs.getString(originKey(index), null); |
michael@0 | 162 | } |
michael@0 | 163 | |
michael@0 | 164 | public int getColor(int index) { |
michael@0 | 165 | return mPrefs.getInt(iconKey(index), -1); |
michael@0 | 166 | } |
michael@0 | 167 | |
michael@0 | 168 | /** |
michael@0 | 169 | * Migrate old prefs to their new equivalents if this app was originally |
michael@0 | 170 | * installed by the shortcut-based implementation. |
michael@0 | 171 | */ |
michael@0 | 172 | public void maybeMigrateOldPrefs(int index) { |
michael@0 | 173 | if (!mPrefs.contains(oldAppKey(index))) { |
michael@0 | 174 | return; |
michael@0 | 175 | } |
michael@0 | 176 | |
michael@0 | 177 | Log.i(LOGTAG, "migrating old prefs"); |
michael@0 | 178 | |
michael@0 | 179 | // The old appKey pref stored the origin, while the new appKey pref |
michael@0 | 180 | // stores the packageName, so we migrate oldAppKey to the origin pref. |
michael@0 | 181 | putOrigin(index, mPrefs.getString(oldAppKey(index), null)); |
michael@0 | 182 | |
michael@0 | 183 | // The old iconKey pref actually stored the splash screen background |
michael@0 | 184 | // color, so we migrate oldIconKey to the color pref. |
michael@0 | 185 | updateColor(index, mPrefs.getInt(oldIconKey(index), -1)); |
michael@0 | 186 | |
michael@0 | 187 | // Remove the old prefs so we don't migrate them the next time around. |
michael@0 | 188 | save(mPrefs.edit().remove(oldAppKey(index)).remove(oldIconKey(index))); |
michael@0 | 189 | } |
michael@0 | 190 | } |