blob: 7d00423a2c41bef35fb51de273e5385caeeb1bac [file] [log] [blame]
Mårten Kongstadeabc9e92015-12-15 16:40:23 +01001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.om;
18
Adam Lesinskid11c5512017-04-11 12:01:10 -070019import static com.android.server.om.OverlayManagerService.DEBUG;
20import static com.android.server.om.OverlayManagerService.TAG;
21
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010022import android.annotation.NonNull;
23import android.annotation.Nullable;
24import android.content.om.OverlayInfo;
Adam Lesinskiada8deb2017-05-12 13:50:42 -070025import android.os.UserHandle;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010026import android.util.AndroidRuntimeException;
27import android.util.ArrayMap;
Adam Lesinskid11c5512017-04-11 12:01:10 -070028import android.util.Slog;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010029import android.util.Xml;
30
31import com.android.internal.util.FastXmlSerializer;
Adam Lesinskiada8deb2017-05-12 13:50:42 -070032import com.android.internal.util.IndentingPrintWriter;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010033import com.android.internal.util.XmlUtils;
34
35import org.xmlpull.v1.XmlPullParser;
36import org.xmlpull.v1.XmlPullParserException;
37
38import java.io.IOException;
39import java.io.InputStream;
40import java.io.InputStreamReader;
41import java.io.OutputStream;
42import java.io.PrintWriter;
43import java.util.ArrayList;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010044import java.util.List;
Adam Lesinskic745f422017-04-05 16:31:30 -070045import java.util.stream.Collectors;
46import java.util.stream.Stream;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010047
48/**
49 * Data structure representing the current state of all overlay packages in the
50 * system.
51 *
Adam Lesinskic745f422017-04-05 16:31:30 -070052 * Modifications to the data are signaled by returning true from any state mutating method.
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010053 *
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010054 * @see OverlayManagerService
55 */
56final class OverlayManagerSettings {
Adam Lesinskic745f422017-04-05 16:31:30 -070057 /**
58 * All overlay data for all users and target packages is stored in this list.
59 * This keeps memory down, while increasing the cost of running queries or mutating the
60 * data. This is ok, since changing of overlays is very rare and has larger costs associated
61 * with it.
62 *
63 * The order of the items in the list is important, those with a lower index having a lower
64 * priority.
65 */
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010066 private final ArrayList<SettingsItem> mItems = new ArrayList<>();
67
68 void init(@NonNull final String packageName, final int userId,
Jaekyun Seok42d53f62017-04-10 13:48:58 +090069 @NonNull final String targetPackageName, @NonNull final String baseCodePath,
70 boolean isStatic, int priority) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010071 remove(packageName, userId);
72 final SettingsItem item =
Jaekyun Seok42d53f62017-04-10 13:48:58 +090073 new SettingsItem(packageName, userId, targetPackageName, baseCodePath,
74 isStatic, priority);
75 if (isStatic) {
76 int i;
77 for (i = mItems.size() - 1; i >= 0; i--) {
78 SettingsItem parentItem = mItems.get(i);
79 if (parentItem.mIsStatic && parentItem.mPriority <= priority) {
80 break;
81 }
82 }
83 int pos = i + 1;
84 if (pos == mItems.size()) {
85 mItems.add(item);
86 } else {
87 mItems.add(pos, item);
88 }
89 } else {
90 mItems.add(item);
91 }
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010092 }
93
Adam Lesinskic745f422017-04-05 16:31:30 -070094 /**
95 * Returns true if the settings were modified, false if they remain the same.
96 */
97 boolean remove(@NonNull final String packageName, final int userId) {
98 final int idx = select(packageName, userId);
99 if (idx < 0) {
100 return false;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100101 }
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100102
Adam Lesinskic745f422017-04-05 16:31:30 -0700103 mItems.remove(idx);
104 return true;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100105 }
106
107 OverlayInfo getOverlayInfo(@NonNull final String packageName, final int userId)
108 throws BadKeyException {
Adam Lesinskic745f422017-04-05 16:31:30 -0700109 final int idx = select(packageName, userId);
110 if (idx < 0) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100111 throw new BadKeyException(packageName, userId);
112 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700113 return mItems.get(idx).getOverlayInfo();
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100114 }
115
Adam Lesinskic745f422017-04-05 16:31:30 -0700116 /**
117 * Returns true if the settings were modified, false if they remain the same.
118 */
119 boolean setBaseCodePath(@NonNull final String packageName, final int userId,
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100120 @NonNull final String path) throws BadKeyException {
Adam Lesinskic745f422017-04-05 16:31:30 -0700121 final int idx = select(packageName, userId);
122 if (idx < 0) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100123 throw new BadKeyException(packageName, userId);
124 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700125 return mItems.get(idx).setBaseCodePath(path);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100126 }
127
128 boolean getEnabled(@NonNull final String packageName, final int userId) throws BadKeyException {
Adam Lesinskic745f422017-04-05 16:31:30 -0700129 final int idx = select(packageName, userId);
130 if (idx < 0) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100131 throw new BadKeyException(packageName, userId);
132 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700133 return mItems.get(idx).isEnabled();
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100134 }
135
Adam Lesinskic745f422017-04-05 16:31:30 -0700136 /**
137 * Returns true if the settings were modified, false if they remain the same.
138 */
139 boolean setEnabled(@NonNull final String packageName, final int userId, final boolean enable)
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100140 throws BadKeyException {
Adam Lesinskic745f422017-04-05 16:31:30 -0700141 final int idx = select(packageName, userId);
142 if (idx < 0) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100143 throw new BadKeyException(packageName, userId);
144 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700145 return mItems.get(idx).setEnabled(enable);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100146 }
147
148 int getState(@NonNull final String packageName, final int userId) throws BadKeyException {
Adam Lesinskic745f422017-04-05 16:31:30 -0700149 final int idx = select(packageName, userId);
150 if (idx < 0) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100151 throw new BadKeyException(packageName, userId);
152 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700153 return mItems.get(idx).getState();
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100154 }
155
Adam Lesinskic745f422017-04-05 16:31:30 -0700156 /**
157 * Returns true if the settings were modified, false if they remain the same.
158 */
159 boolean setState(@NonNull final String packageName, final int userId, final int state)
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100160 throws BadKeyException {
Adam Lesinskic745f422017-04-05 16:31:30 -0700161 final int idx = select(packageName, userId);
162 if (idx < 0) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100163 throw new BadKeyException(packageName, userId);
164 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700165 return mItems.get(idx).setState(state);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100166 }
167
168 List<OverlayInfo> getOverlaysForTarget(@NonNull final String targetPackageName,
169 final int userId) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700170 return selectWhereTarget(targetPackageName, userId)
171 .map(SettingsItem::getOverlayInfo)
172 .collect(Collectors.toList());
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100173 }
174
175 ArrayMap<String, List<OverlayInfo>> getOverlaysForUser(final int userId) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700176 return selectWhereUser(userId)
177 .map(SettingsItem::getOverlayInfo)
178 .collect(Collectors.groupingBy(info -> info.targetPackageName, ArrayMap::new,
179 Collectors.toList()));
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100180 }
181
Adam Lesinskic745f422017-04-05 16:31:30 -0700182 int[] getUsers() {
183 return mItems.stream().mapToInt(SettingsItem::getUserId).distinct().toArray();
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100184 }
185
Adam Lesinskic745f422017-04-05 16:31:30 -0700186 /**
187 * Returns true if the settings were modified, false if they remain the same.
188 */
189 boolean removeUser(final int userId) {
190 boolean removed = false;
191 for (int i = 0; i < mItems.size(); i++) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100192 final SettingsItem item = mItems.get(i);
Adam Lesinskic745f422017-04-05 16:31:30 -0700193 if (item.getUserId() == userId) {
Adam Lesinskid11c5512017-04-11 12:01:10 -0700194 if (DEBUG) {
195 Slog.d(TAG, "Removing overlay " + item.mPackageName + " for user " + userId
196 + " from settings because user was removed");
197 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700198 mItems.remove(i);
199 removed = true;
200 i--;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100201 }
202 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700203 return removed;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100204 }
205
Adam Lesinskic745f422017-04-05 16:31:30 -0700206 /**
207 * Returns true if the settings were modified, false if they remain the same.
208 */
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100209 boolean setPriority(@NonNull final String packageName,
210 @NonNull final String newParentPackageName, final int userId) {
211 if (packageName.equals(newParentPackageName)) {
212 return false;
213 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700214 final int moveIdx = select(packageName, userId);
215 if (moveIdx < 0) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100216 return false;
217 }
218
Adam Lesinskic745f422017-04-05 16:31:30 -0700219 final int parentIdx = select(newParentPackageName, userId);
220 if (parentIdx < 0) {
221 return false;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100222 }
223
Adam Lesinskic745f422017-04-05 16:31:30 -0700224 final SettingsItem itemToMove = mItems.get(moveIdx);
225
226 // Make sure both packages are targeting the same package.
227 if (!itemToMove.getTargetPackageName().equals(
228 mItems.get(parentIdx).getTargetPackageName())) {
229 return false;
230 }
231
232 mItems.remove(moveIdx);
Mårten Kongstadb1fe5152018-01-23 00:23:51 -0800233 final int newParentIdx = select(newParentPackageName, userId) + 1;
Adam Lesinskic745f422017-04-05 16:31:30 -0700234 mItems.add(newParentIdx, itemToMove);
235 return moveIdx != newParentIdx;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100236 }
237
Adam Lesinskic745f422017-04-05 16:31:30 -0700238 /**
239 * Returns true if the settings were modified, false if they remain the same.
240 */
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100241 boolean setLowestPriority(@NonNull final String packageName, final int userId) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700242 final int idx = select(packageName, userId);
243 if (idx <= 0) {
244 // If the item doesn't exist or is already the lowest, don't change anything.
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100245 return false;
246 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700247
248 final SettingsItem item = mItems.get(idx);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100249 mItems.remove(item);
250 mItems.add(0, item);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100251 return true;
252 }
253
Adam Lesinskic745f422017-04-05 16:31:30 -0700254 /**
255 * Returns true if the settings were modified, false if they remain the same.
256 */
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100257 boolean setHighestPriority(@NonNull final String packageName, final int userId) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700258 final int idx = select(packageName, userId);
259
260 // If the item doesn't exist or is already the highest, don't change anything.
261 if (idx < 0 || idx == mItems.size() - 1) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100262 return false;
263 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700264
265 final SettingsItem item = mItems.get(idx);
266 mItems.remove(idx);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100267 mItems.add(item);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100268 return true;
269 }
270
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700271 void dump(@NonNull final PrintWriter p) {
272 final IndentingPrintWriter pw = new IndentingPrintWriter(p, " ");
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100273 pw.println("Settings");
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700274 pw.increaseIndent();
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100275
276 if (mItems.isEmpty()) {
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700277 pw.println("<none>");
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100278 return;
279 }
280
281 final int N = mItems.size();
282 for (int i = 0; i < N; i++) {
283 final SettingsItem item = mItems.get(i);
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700284 pw.println(item.mPackageName + ":" + item.getUserId() + " {");
285 pw.increaseIndent();
286
287 pw.print("mPackageName.......: "); pw.println(item.mPackageName);
288 pw.print("mUserId............: "); pw.println(item.getUserId());
289 pw.print("mTargetPackageName.: "); pw.println(item.getTargetPackageName());
290 pw.print("mBaseCodePath......: "); pw.println(item.getBaseCodePath());
291 pw.print("mState.............: "); pw.println(OverlayInfo.stateToString(item.getState()));
292 pw.print("mIsEnabled.........: "); pw.println(item.isEnabled());
293 pw.print("mIsStatic..........: "); pw.println(item.isStatic());
294
295 pw.decreaseIndent();
296 pw.println("}");
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100297 }
298 }
299
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100300 void restore(@NonNull final InputStream is) throws IOException, XmlPullParserException {
301 Serializer.restore(mItems, is);
302 }
303
304 void persist(@NonNull final OutputStream os) throws IOException, XmlPullParserException {
305 Serializer.persist(mItems, os);
306 }
307
308 private static final class Serializer {
309 private static final String TAG_OVERLAYS = "overlays";
310 private static final String TAG_ITEM = "item";
311
312 private static final String ATTR_BASE_CODE_PATH = "baseCodePath";
313 private static final String ATTR_IS_ENABLED = "isEnabled";
314 private static final String ATTR_PACKAGE_NAME = "packageName";
315 private static final String ATTR_STATE = "state";
316 private static final String ATTR_TARGET_PACKAGE_NAME = "targetPackageName";
Jaekyun Seok42d53f62017-04-10 13:48:58 +0900317 private static final String ATTR_IS_STATIC = "isStatic";
318 private static final String ATTR_PRIORITY = "priority";
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100319 private static final String ATTR_USER_ID = "userId";
320 private static final String ATTR_VERSION = "version";
321
Andrew Sapperstein5e1953a2017-05-22 12:46:51 -0700322 private static final int CURRENT_VERSION = 3;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100323
324 public static void restore(@NonNull final ArrayList<SettingsItem> table,
325 @NonNull final InputStream is) throws IOException, XmlPullParserException {
326
327 try (InputStreamReader reader = new InputStreamReader(is)) {
328 table.clear();
329 final XmlPullParser parser = Xml.newPullParser();
330 parser.setInput(reader);
331 XmlUtils.beginDocument(parser, TAG_OVERLAYS);
332 int version = XmlUtils.readIntAttribute(parser, ATTR_VERSION);
333 if (version != CURRENT_VERSION) {
Adam Lesinskid68e9182017-03-06 12:52:58 -0800334 upgrade(version);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100335 }
336 int depth = parser.getDepth();
337
338 while (XmlUtils.nextElementWithin(parser, depth)) {
339 switch (parser.getName()) {
340 case TAG_ITEM:
341 final SettingsItem item = restoreRow(parser, depth + 1);
342 table.add(item);
343 break;
344 }
345 }
346 }
347 }
348
Adam Lesinskid68e9182017-03-06 12:52:58 -0800349 private static void upgrade(int oldVersion) throws XmlPullParserException {
350 switch (oldVersion) {
351 case 0:
352 case 1:
Andrew Sapperstein5e1953a2017-05-22 12:46:51 -0700353 case 2:
Adam Lesinskid68e9182017-03-06 12:52:58 -0800354 // Throw an exception which will cause the overlay file to be ignored
355 // and overwritten.
356 throw new XmlPullParserException("old version " + oldVersion + "; ignoring");
357 default:
358 throw new XmlPullParserException("unrecognized version " + oldVersion);
359 }
360 }
361
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100362 private static SettingsItem restoreRow(@NonNull final XmlPullParser parser, final int depth)
363 throws IOException {
364 final String packageName = XmlUtils.readStringAttribute(parser, ATTR_PACKAGE_NAME);
365 final int userId = XmlUtils.readIntAttribute(parser, ATTR_USER_ID);
366 final String targetPackageName = XmlUtils.readStringAttribute(parser,
367 ATTR_TARGET_PACKAGE_NAME);
368 final String baseCodePath = XmlUtils.readStringAttribute(parser, ATTR_BASE_CODE_PATH);
369 final int state = XmlUtils.readIntAttribute(parser, ATTR_STATE);
370 final boolean isEnabled = XmlUtils.readBooleanAttribute(parser, ATTR_IS_ENABLED);
Jaekyun Seok42d53f62017-04-10 13:48:58 +0900371 final boolean isStatic = XmlUtils.readBooleanAttribute(parser, ATTR_IS_STATIC);
372 final int priority = XmlUtils.readIntAttribute(parser, ATTR_PRIORITY);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100373
374 return new SettingsItem(packageName, userId, targetPackageName, baseCodePath, state,
Jaekyun Seok42d53f62017-04-10 13:48:58 +0900375 isEnabled, isStatic, priority);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100376 }
377
378 public static void persist(@NonNull final ArrayList<SettingsItem> table,
379 @NonNull final OutputStream os) throws IOException, XmlPullParserException {
380 final FastXmlSerializer xml = new FastXmlSerializer();
381 xml.setOutput(os, "utf-8");
382 xml.startDocument(null, true);
383 xml.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
384 xml.startTag(null, TAG_OVERLAYS);
385 XmlUtils.writeIntAttribute(xml, ATTR_VERSION, CURRENT_VERSION);
386
387 final int N = table.size();
388 for (int i = 0; i < N; i++) {
389 final SettingsItem item = table.get(i);
390 persistRow(xml, item);
391 }
392 xml.endTag(null, TAG_OVERLAYS);
393 xml.endDocument();
394 }
395
396 private static void persistRow(@NonNull final FastXmlSerializer xml,
397 @NonNull final SettingsItem item) throws IOException {
398 xml.startTag(null, TAG_ITEM);
Adam Lesinskic745f422017-04-05 16:31:30 -0700399 XmlUtils.writeStringAttribute(xml, ATTR_PACKAGE_NAME, item.mPackageName);
400 XmlUtils.writeIntAttribute(xml, ATTR_USER_ID, item.mUserId);
401 XmlUtils.writeStringAttribute(xml, ATTR_TARGET_PACKAGE_NAME, item.mTargetPackageName);
402 XmlUtils.writeStringAttribute(xml, ATTR_BASE_CODE_PATH, item.mBaseCodePath);
403 XmlUtils.writeIntAttribute(xml, ATTR_STATE, item.mState);
404 XmlUtils.writeBooleanAttribute(xml, ATTR_IS_ENABLED, item.mIsEnabled);
Jaekyun Seok42d53f62017-04-10 13:48:58 +0900405 XmlUtils.writeBooleanAttribute(xml, ATTR_IS_STATIC, item.mIsStatic);
406 XmlUtils.writeIntAttribute(xml, ATTR_PRIORITY, item.mPriority);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100407 xml.endTag(null, TAG_ITEM);
408 }
409 }
410
411 private static final class SettingsItem {
Adam Lesinskic745f422017-04-05 16:31:30 -0700412 private final int mUserId;
413 private final String mPackageName;
414 private final String mTargetPackageName;
415 private String mBaseCodePath;
416 private int mState;
417 private boolean mIsEnabled;
418 private OverlayInfo mCache;
Jaekyun Seok42d53f62017-04-10 13:48:58 +0900419 private boolean mIsStatic;
420 private int mPriority;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100421
422 SettingsItem(@NonNull final String packageName, final int userId,
423 @NonNull final String targetPackageName, @NonNull final String baseCodePath,
Jaekyun Seok42d53f62017-04-10 13:48:58 +0900424 final int state, final boolean isEnabled, final boolean isStatic,
425 final int priority) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700426 mPackageName = packageName;
427 mUserId = userId;
428 mTargetPackageName = targetPackageName;
429 mBaseCodePath = baseCodePath;
430 mState = state;
431 mIsEnabled = isEnabled;
432 mCache = null;
Jaekyun Seok42d53f62017-04-10 13:48:58 +0900433 mIsStatic = isStatic;
434 mPriority = priority;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100435 }
436
437 SettingsItem(@NonNull final String packageName, final int userId,
Jaekyun Seok42d53f62017-04-10 13:48:58 +0900438 @NonNull final String targetPackageName, @NonNull final String baseCodePath,
439 final boolean isStatic, final int priority) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700440 this(packageName, userId, targetPackageName, baseCodePath, OverlayInfo.STATE_UNKNOWN,
Jaekyun Seok42d53f62017-04-10 13:48:58 +0900441 false, isStatic, priority);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100442 }
443
444 private String getTargetPackageName() {
Adam Lesinskic745f422017-04-05 16:31:30 -0700445 return mTargetPackageName;
446 }
447
448 private int getUserId() {
449 return mUserId;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100450 }
451
452 private String getBaseCodePath() {
Adam Lesinskic745f422017-04-05 16:31:30 -0700453 return mBaseCodePath;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100454 }
455
Adam Lesinskic745f422017-04-05 16:31:30 -0700456 private boolean setBaseCodePath(@NonNull final String path) {
457 if (!mBaseCodePath.equals(path)) {
458 mBaseCodePath = path;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100459 invalidateCache();
Adam Lesinskic745f422017-04-05 16:31:30 -0700460 return true;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100461 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700462 return false;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100463 }
464
465 private int getState() {
Adam Lesinskic745f422017-04-05 16:31:30 -0700466 return mState;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100467 }
468
Adam Lesinskic745f422017-04-05 16:31:30 -0700469 private boolean setState(final int state) {
470 if (mState != state) {
471 mState = state;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100472 invalidateCache();
Adam Lesinskic745f422017-04-05 16:31:30 -0700473 return true;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100474 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700475 return false;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100476 }
477
478 private boolean isEnabled() {
Adam Lesinskic745f422017-04-05 16:31:30 -0700479 return mIsEnabled;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100480 }
481
Adam Lesinskic745f422017-04-05 16:31:30 -0700482 private boolean setEnabled(final boolean enable) {
483 if (mIsEnabled != enable) {
484 mIsEnabled = enable;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100485 invalidateCache();
Adam Lesinskic745f422017-04-05 16:31:30 -0700486 return true;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100487 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700488 return false;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100489 }
490
491 private OverlayInfo getOverlayInfo() {
Adam Lesinskic745f422017-04-05 16:31:30 -0700492 if (mCache == null) {
493 mCache = new OverlayInfo(mPackageName, mTargetPackageName, mBaseCodePath, mState,
494 mUserId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100495 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700496 return mCache;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100497 }
498
499 private void invalidateCache() {
Adam Lesinskic745f422017-04-05 16:31:30 -0700500 mCache = null;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100501 }
Jaekyun Seok42d53f62017-04-10 13:48:58 +0900502
503 private boolean isStatic() {
504 return mIsStatic;
505 }
506
507 private int getPriority() {
508 return mPriority;
509 }
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100510 }
511
Adam Lesinskic745f422017-04-05 16:31:30 -0700512 private int select(@NonNull final String packageName, final int userId) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100513 final int N = mItems.size();
514 for (int i = 0; i < N; i++) {
515 final SettingsItem item = mItems.get(i);
Adam Lesinskic745f422017-04-05 16:31:30 -0700516 if (item.mUserId == userId && item.mPackageName.equals(packageName)) {
517 return i;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100518 }
519 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700520 return -1;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100521 }
522
Adam Lesinskic745f422017-04-05 16:31:30 -0700523 private Stream<SettingsItem> selectWhereUser(final int userId) {
524 return mItems.stream().filter(item -> item.mUserId == userId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100525 }
526
Adam Lesinskic745f422017-04-05 16:31:30 -0700527 private Stream<SettingsItem> selectWhereTarget(@NonNull final String targetPackageName,
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100528 final int userId) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700529 return selectWhereUser(userId)
530 .filter(item -> item.getTargetPackageName().equals(targetPackageName));
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100531 }
532
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100533 static final class BadKeyException extends RuntimeException {
534 BadKeyException(@NonNull final String packageName, final int userId) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700535 super("Bad key mPackageName=" + packageName + " mUserId=" + userId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100536 }
537 }
538}