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