Merge "OverlayManagerService: Make broadcasts/updates explicit" into oc-dev

am: ec8f353668

Change-Id: Ied4fc0b2fe79c69e6fd1b8677a5d615300119b39
This commit is contained in:
Adam Lesinski
2017-04-11 00:13:41 +00:00
committed by android-build-merger
4 changed files with 349 additions and 467 deletions

View File

@@ -3215,13 +3215,6 @@ public class Intent implements Parcelable, Cloneable {
public static final String ACTION_MEDIA_RESOURCE_GRANTED = public static final String ACTION_MEDIA_RESOURCE_GRANTED =
"android.intent.action.MEDIA_RESOURCE_GRANTED"; "android.intent.action.MEDIA_RESOURCE_GRANTED";
/**
* Broadcast Action: An overlay package has been installed. The data
* contains the name of the added overlay package.
* @hide
*/
public static final String ACTION_OVERLAY_ADDED = "android.intent.action.OVERLAY_ADDED";
/** /**
* Broadcast Action: An overlay package has changed. The data contains the * Broadcast Action: An overlay package has changed. The data contains the
* name of the overlay package which has changed. This is broadcast on all * name of the overlay package which has changed. This is broadcast on all
@@ -3233,22 +3226,6 @@ public class Intent implements Parcelable, Cloneable {
*/ */
public static final String ACTION_OVERLAY_CHANGED = "android.intent.action.OVERLAY_CHANGED"; public static final String ACTION_OVERLAY_CHANGED = "android.intent.action.OVERLAY_CHANGED";
/**
* Broadcast Action: An overlay package has been removed. The data contains
* the name of the overlay package which has been removed.
* @hide
*/
public static final String ACTION_OVERLAY_REMOVED = "android.intent.action.OVERLAY_REMOVED";
/**
* Broadcast Action: The order of a package's list of overlay packages has
* changed. The data contains the package name of the overlay package that
* had its position in the list adjusted.
* @hide
*/
public static final String
ACTION_OVERLAY_PRIORITY_CHANGED = "android.intent.action.OVERLAY_PRIORITY_CHANGED";
/** /**
* Activity Action: Allow the user to select and return one or more existing * Activity Action: Allow the user to select and return one or more existing
* documents. When invoked, the system will display the various * documents. When invoked, the system will display the various

View File

@@ -193,13 +193,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
* </ul> * </ul>
*/ */
public final class OverlayManagerService extends SystemService { public final class OverlayManagerService extends SystemService {
static final String TAG = "OverlayManager"; static final String TAG = "OverlayManager";
static final boolean DEBUG = false; static final boolean DEBUG = false;
static final String PERMISSION_DENIED = "Operation not permitted for user shell";
/** /**
* The system property that specifies the default overlays to apply. * The system property that specifies the default overlays to apply.
* This is a semicolon separated list of package names. * This is a semicolon separated list of package names.
@@ -234,7 +231,7 @@ public final class OverlayManagerService extends SystemService {
IdmapManager im = new IdmapManager(installer); IdmapManager im = new IdmapManager(installer);
mSettings = new OverlayManagerSettings(); mSettings = new OverlayManagerSettings();
mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings, mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
getDefaultOverlayPackages()); getDefaultOverlayPackages(), new OverlayChangeListener());
mInitCompleteSignal = SystemServerInitThreadPool.get().submit(() -> { mInitCompleteSignal = SystemServerInitThreadPool.get().submit(() -> {
final IntentFilter packageFilter = new IntentFilter(); final IntentFilter packageFilter = new IntentFilter();
packageFilter.addAction(ACTION_PACKAGE_ADDED); packageFilter.addAction(ACTION_PACKAGE_ADDED);
@@ -251,9 +248,6 @@ public final class OverlayManagerService extends SystemService {
restoreSettings(); restoreSettings();
onSwitchUser(UserHandle.USER_SYSTEM); onSwitchUser(UserHandle.USER_SYSTEM);
schedulePersistSettings();
mSettings.addChangeListener(new OverlayChangeListener());
publishBinderService(Context.OVERLAY_SERVICE, mService); publishBinderService(Context.OVERLAY_SERVICE, mService);
publishLocalService(OverlayManagerService.class, this); publishLocalService(OverlayManagerService.class, this);
@@ -281,8 +275,9 @@ public final class OverlayManagerService extends SystemService {
final List<String> targets; final List<String> targets;
synchronized (mLock) { synchronized (mLock) {
targets = mImpl.onSwitchUser(newUserId); targets = mImpl.onSwitchUser(newUserId);
updateAssetsLocked(newUserId, targets);
} }
updateAssets(newUserId, targets); schedulePersistSettings();
} }
private static Set<String> getDefaultOverlayPackages() { private static Set<String> getDefaultOverlayPackages() {
@@ -348,7 +343,8 @@ public final class OverlayManagerService extends SystemService {
@NonNull final int[] userIds) { @NonNull final int[] userIds) {
for (final int userId : userIds) { for (final int userId : userIds) {
synchronized (mLock) { synchronized (mLock) {
final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, false); final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
false);
if (pi != null) { if (pi != null) {
mPackageManager.cachePackageInfo(packageName, userId, pi); mPackageManager.cachePackageInfo(packageName, userId, pi);
if (!isOverlayPackage(pi)) { if (!isOverlayPackage(pi)) {
@@ -365,7 +361,8 @@ public final class OverlayManagerService extends SystemService {
@NonNull final int[] userIds) { @NonNull final int[] userIds) {
for (int userId : userIds) { for (int userId : userIds) {
synchronized (mLock) { synchronized (mLock) {
final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, false); final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
false);
if (pi != null) { if (pi != null) {
mPackageManager.cachePackageInfo(packageName, userId, pi); mPackageManager.cachePackageInfo(packageName, userId, pi);
if (!isOverlayPackage(pi)) { if (!isOverlayPackage(pi)) {
@@ -397,7 +394,8 @@ public final class OverlayManagerService extends SystemService {
@NonNull final int[] userIds) { @NonNull final int[] userIds) {
for (int userId : userIds) { for (int userId : userIds) {
synchronized (mLock) { synchronized (mLock) {
final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, false); final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
false);
if (pi != null) { if (pi != null) {
mPackageManager.cachePackageInfo(packageName, userId, pi); mPackageManager.cachePackageInfo(packageName, userId, pi);
if (!isOverlayPackage(pi)) { if (!isOverlayPackage(pi)) {
@@ -449,8 +447,7 @@ public final class OverlayManagerService extends SystemService {
private final IBinder mService = new IOverlayManager.Stub() { private final IBinder mService = new IOverlayManager.Stub() {
@Override @Override
public Map<String, List<OverlayInfo>> getAllOverlays(int userId) public Map<String, List<OverlayInfo>> getAllOverlays(int userId) throws RemoteException {
throws RemoteException {
userId = handleIncomingUser(userId, "getAllOverlays"); userId = handleIncomingUser(userId, "getAllOverlays");
synchronized (mLock) { synchronized (mLock) {
@@ -508,14 +505,14 @@ public final class OverlayManagerService extends SystemService {
int userId) throws RemoteException { int userId) throws RemoteException {
enforceChangeOverlayPackagesPermission("setEnabled"); enforceChangeOverlayPackagesPermission("setEnabled");
userId = handleIncomingUser(userId, "setEnabled"); userId = handleIncomingUser(userId, "setEnabled");
if (packageName == null) { if (packageName == null || !enable) {
return false; return false;
} }
final long ident = Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity();
try { try {
synchronized (mLock) { synchronized (mLock) {
return mImpl.setEnabledExclusive(packageName, enable, userId); return mImpl.setEnabledExclusive(packageName, userId);
} }
} finally { } finally {
Binder.restoreCallingIdentity(ident); Binder.restoreCallingIdentity(ident);
@@ -643,68 +640,24 @@ public final class OverlayManagerService extends SystemService {
return pi != null && pi.overlayTarget != null; return pi != null && pi.overlayTarget != null;
} }
private final class OverlayChangeListener implements OverlayManagerSettings.ChangeListener { private final class OverlayChangeListener
implements OverlayManagerServiceImpl.OverlayChangeListener {
@Override @Override
public void onSettingsChanged() { public void onOverlaysChanged(@NonNull final String targetPackageName, final int userId) {
schedulePersistSettings(); schedulePersistSettings();
} FgThread.getHandler().post(() -> {
synchronized (mLock) {
@Override updateAssetsLocked(userId, targetPackageName);
public void onOverlayAdded(@NonNull final OverlayInfo oi) {
scheduleBroadcast(Intent.ACTION_OVERLAY_ADDED, oi, oi.isEnabled());
}
@Override
public void onOverlayRemoved(@NonNull final OverlayInfo oi) {
scheduleBroadcast(Intent.ACTION_OVERLAY_REMOVED, oi, oi.isEnabled());
}
@Override
public void onOverlayChanged(@NonNull final OverlayInfo oi,
@NonNull final OverlayInfo oldOi) {
scheduleBroadcast(Intent.ACTION_OVERLAY_CHANGED, oi, oi.isEnabled() != oldOi.isEnabled());
}
@Override
public void onOverlayPriorityChanged(@NonNull final OverlayInfo oi) {
scheduleBroadcast(Intent.ACTION_OVERLAY_PRIORITY_CHANGED, oi, oi.isEnabled());
}
private void scheduleBroadcast(@NonNull final String action, @NonNull final OverlayInfo oi,
final boolean doUpdate) {
FgThread.getHandler().post(new BroadcastRunnable(action, oi, doUpdate));
}
private final class BroadcastRunnable implements Runnable {
private final String mAction;
private final OverlayInfo mOverlayInfo;
private final boolean mDoUpdate;
BroadcastRunnable(@NonNull final String action, @NonNull final OverlayInfo oi,
final boolean doUpdate) {
mAction = action;
mOverlayInfo = oi;
mDoUpdate = doUpdate;
}
@Override
public void run() {
if (mDoUpdate) {
updateAssets(mOverlayInfo.userId, mOverlayInfo.targetPackageName);
} }
sendBroadcast(mAction, mOverlayInfo.targetPackageName, mOverlayInfo.packageName,
mOverlayInfo.userId);
}
private void sendBroadcast(@NonNull final String action, final Intent intent = new Intent(Intent.ACTION_OVERLAY_CHANGED,
@NonNull final String targetPackageName, @NonNull final String packageName, Uri.fromParts("package", targetPackageName, null));
final int userId) {
final Intent intent = new Intent(action, Uri.fromParts("package",
String.format("%s/%s", targetPackageName, packageName), null));
intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
if (DEBUG) { if (DEBUG) {
Slog.d(TAG, String.format("send broadcast %s", intent)); Slog.d(TAG, "send broadcast " + intent);
} }
try { try {
ActivityManager.getService().broadcastIntent(null, intent, null, null, 0, ActivityManager.getService().broadcastIntent(null, intent, null, null, 0,
null, null, null, android.app.AppOpsManager.OP_NONE, null, false, false, null, null, null, android.app.AppOpsManager.OP_NONE, null, false, false,
@@ -712,18 +665,20 @@ public final class OverlayManagerService extends SystemService {
} catch (RemoteException e) { } catch (RemoteException e) {
// Intentionally left empty. // Intentionally left empty.
} }
} });
} }
} }
private void updateAssets(final int userId, final String targetPackageName) { private void updateAssetsLocked(final int userId, final String targetPackageName) {
final List<String> list = new ArrayList<>(); final List<String> list = new ArrayList<>();
list.add(targetPackageName); list.add(targetPackageName);
updateAssets(userId, list); updateAssetsLocked(userId, list);
} }
private void updateAssets(final int userId, List<String> targetPackageNames) { private void updateAssetsLocked(final int userId, List<String> targetPackageNames) {
if (DEBUG) {
Slog.d(TAG, "Updating overlay assets");
}
final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class); final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
final boolean updateFrameworkRes = targetPackageNames.contains("android"); final boolean updateFrameworkRes = targetPackageNames.contains("android");
if (updateFrameworkRes) { if (updateFrameworkRes) {
@@ -743,6 +698,12 @@ public final class OverlayManagerService extends SystemService {
final int N = targetPackageNames.size(); final int N = targetPackageNames.size();
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
final String targetPackageName = targetPackageNames.get(i); final String targetPackageName = targetPackageNames.get(i);
if (DEBUG) {
Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=["
+ TextUtils.join(",", pendingChanges.get(targetPackageName))
+ "] userId=" + userId);
}
if (!pm.setEnabledOverlayPackages( if (!pm.setEnabledOverlayPackages(
userId, targetPackageName, pendingChanges.get(targetPackageName))) { userId, targetPackageName, pendingChanges.get(targetPackageName))) {
Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d", Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
@@ -762,20 +723,20 @@ public final class OverlayManagerService extends SystemService {
if (mPersistSettingsScheduled.getAndSet(true)) { if (mPersistSettingsScheduled.getAndSet(true)) {
return; return;
} }
IoThread.getHandler().post(new Runnable() { IoThread.getHandler().post(() -> {
@Override mPersistSettingsScheduled.set(false);
public void run() { if (DEBUG) {
mPersistSettingsScheduled.set(false); Slog.d(TAG, "Writing overlay settings");
synchronized (mLock) { }
FileOutputStream stream = null; synchronized (mLock) {
try { FileOutputStream stream = null;
stream = mSettingsFile.startWrite(); try {
mSettings.persist(stream); stream = mSettingsFile.startWrite();
mSettingsFile.finishWrite(stream); mSettings.persist(stream);
} catch (IOException | XmlPullParserException e) { mSettingsFile.finishWrite(stream);
mSettingsFile.failWrite(stream); } catch (IOException | XmlPullParserException e) {
Slog.e(TAG, "failed to persist overlay state", e); mSettingsFile.failWrite(stream);
} Slog.e(TAG, "failed to persist overlay state", e);
} }
} }
}); });
@@ -862,7 +823,8 @@ public final class OverlayManagerService extends SystemService {
// The package manager does not support different versions of packages // The package manager does not support different versions of packages
// to be installed for different users: ignore userId for now. // to be installed for different users: ignore userId for now.
try { try {
return mPackageManager.checkSignatures(packageName1, packageName2) == SIGNATURE_MATCH; return mPackageManager.checkSignatures(
packageName1, packageName2) == SIGNATURE_MATCH;
} catch (RemoteException e) { } catch (RemoteException e) {
// Intentionally left blank // Intentionally left blank
} }

View File

@@ -54,15 +54,18 @@ final class OverlayManagerServiceImpl {
private final IdmapManager mIdmapManager; private final IdmapManager mIdmapManager;
private final OverlayManagerSettings mSettings; private final OverlayManagerSettings mSettings;
private final Set<String> mDefaultOverlays; private final Set<String> mDefaultOverlays;
private final OverlayChangeListener mListener;
OverlayManagerServiceImpl(@NonNull final PackageManagerHelper packageManager, OverlayManagerServiceImpl(@NonNull final PackageManagerHelper packageManager,
@NonNull final IdmapManager idmapManager, @NonNull final IdmapManager idmapManager,
@NonNull final OverlayManagerSettings settings, @NonNull final OverlayManagerSettings settings,
@NonNull final Set<String> defaultOverlays) { @NonNull final Set<String> defaultOverlays,
@NonNull final OverlayChangeListener listener) {
mPackageManager = packageManager; mPackageManager = packageManager;
mIdmapManager = idmapManager; mIdmapManager = idmapManager;
mSettings = settings; mSettings = settings;
mDefaultOverlays = defaultOverlays; mDefaultOverlays = defaultOverlays;
mListener = listener;
} }
/* /*
@@ -145,7 +148,6 @@ final class OverlayManagerServiceImpl {
iter.remove(); iter.remove();
} }
} }
return new ArrayList<>(packagesToUpdateAssets); return new ArrayList<>(packagesToUpdateAssets);
} }
@@ -199,25 +201,30 @@ final class OverlayManagerServiceImpl {
updateAllOverlaysForTarget(packageName, userId, null); updateAllOverlaysForTarget(packageName, userId, null);
} }
private void updateAllOverlaysForTarget(@NonNull final String packageName, final int userId, /**
* Returns true if the settings were modified for this target.
*/
private boolean updateAllOverlaysForTarget(@NonNull final String packageName, final int userId,
@Nullable final PackageInfo targetPackage) { @Nullable final PackageInfo targetPackage) {
boolean modified = false;
final List<OverlayInfo> ois = mSettings.getOverlaysForTarget(packageName, userId); final List<OverlayInfo> ois = mSettings.getOverlaysForTarget(packageName, userId);
final int N = ois.size(); final int N = ois.size();
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
final OverlayInfo oi = ois.get(i); final OverlayInfo oi = ois.get(i);
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(oi.packageName, userId); final PackageInfo overlayPackage = mPackageManager.getPackageInfo(oi.packageName, userId);
if (overlayPackage == null) { if (overlayPackage == null) {
mSettings.remove(oi.packageName, oi.userId); modified |= mSettings.remove(oi.packageName, oi.userId);
removeIdmapIfPossible(oi); removeIdmapIfPossible(oi);
} else { } else {
try { try {
updateState(targetPackage, overlayPackage, userId); modified |= updateState(targetPackage, overlayPackage, userId);
} catch (OverlayManagerSettings.BadKeyException e) { } catch (OverlayManagerSettings.BadKeyException e) {
Slog.e(TAG, "failed to update settings", e); Slog.e(TAG, "failed to update settings", e);
mSettings.remove(oi.packageName, userId); modified |= mSettings.remove(oi.packageName, userId);
} }
} }
} }
return modified;
} }
void onOverlayPackageAdded(@NonNull final String packageName, final int userId) { void onOverlayPackageAdded(@NonNull final String packageName, final int userId) {
@@ -238,7 +245,9 @@ final class OverlayManagerServiceImpl {
mSettings.init(packageName, userId, overlayPackage.overlayTarget, mSettings.init(packageName, userId, overlayPackage.overlayTarget,
overlayPackage.applicationInfo.getBaseCodePath()); overlayPackage.applicationInfo.getBaseCodePath());
try { try {
updateState(targetPackage, overlayPackage, userId); if (updateState(targetPackage, overlayPackage, userId)) {
mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
}
} catch (OverlayManagerSettings.BadKeyException e) { } catch (OverlayManagerSettings.BadKeyException e) {
Slog.e(TAG, "failed to update settings", e); Slog.e(TAG, "failed to update settings", e);
mSettings.remove(packageName, userId); mSettings.remove(packageName, userId);
@@ -289,8 +298,9 @@ final class OverlayManagerServiceImpl {
if (overlayPackage == null) { if (overlayPackage == null) {
return false; return false;
} }
// Static overlay is always being enabled.
if (!enable && overlayPackage.isStaticOverlay) { // Ignore static overlays.
if (overlayPackage.isStaticOverlay) {
return false; return false;
} }
@@ -298,19 +308,21 @@ final class OverlayManagerServiceImpl {
final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId); final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
final PackageInfo targetPackage = final PackageInfo targetPackage =
mPackageManager.getPackageInfo(oi.targetPackageName, userId); mPackageManager.getPackageInfo(oi.targetPackageName, userId);
mSettings.setEnabled(packageName, userId, enable); boolean modified = mSettings.setEnabled(packageName, userId, enable);
updateState(targetPackage, overlayPackage, userId); modified |= updateState(targetPackage, overlayPackage, userId);
if (modified) {
mListener.onOverlaysChanged(oi.targetPackageName, userId);
}
return true; return true;
} catch (OverlayManagerSettings.BadKeyException e) { } catch (OverlayManagerSettings.BadKeyException e) {
return false; return false;
} }
} }
boolean setEnabledExclusive(@NonNull final String packageName, final boolean enable, boolean setEnabledExclusive(@NonNull final String packageName, final int userId) {
final int userId) {
if (DEBUG) { if (DEBUG) {
Slog.d(TAG, String.format("setEnabled packageName=%s enable=%s userId=%d", Slog.d(TAG, String.format("setEnabledExclusive packageName=%s userId=%d", packageName, userId));
packageName, enable, userId));
} }
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId); final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
@@ -320,23 +332,48 @@ final class OverlayManagerServiceImpl {
try { try {
final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId); final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
final PackageInfo targetPackage =
mPackageManager.getPackageInfo(oi.targetPackageName, userId);
List<OverlayInfo> allOverlays = getOverlayInfosForTarget(oi.targetPackageName, userId); List<OverlayInfo> allOverlays = getOverlayInfosForTarget(oi.targetPackageName, userId);
boolean modified = false;
// Disable all other overlays. // Disable all other overlays.
allOverlays.remove(oi); allOverlays.remove(oi);
for (int i = 0; i < allOverlays.size(); i++) { for (int i = 0; i < allOverlays.size(); i++) {
// TODO: Optimize this to only send updates after all changes. final String disabledOverlayPackageName = allOverlays.get(i).packageName;
setEnabled(allOverlays.get(i).packageName, false, userId); final PackageInfo disabledOverlayPackageInfo = mPackageManager.getPackageInfo(
disabledOverlayPackageName, userId);
if (disabledOverlayPackageInfo == null) {
modified |= mSettings.remove(disabledOverlayPackageName, userId);
continue;
}
if (disabledOverlayPackageInfo.isStaticOverlay) {
// Don't touch static overlays.
continue;
}
// Disable the overlay.
modified |= mSettings.setEnabled(disabledOverlayPackageName, userId, false);
modified |= updateState(targetPackage, disabledOverlayPackageInfo, userId);
} }
setEnabled(packageName, enable, userId); // Enable the selected overlay.
modified |= mSettings.setEnabled(packageName, userId, true);
modified |= updateState(targetPackage, overlayPackage, userId);
if (modified) {
mListener.onOverlaysChanged(oi.targetPackageName, userId);
}
return true; return true;
} catch (OverlayManagerSettings.BadKeyException e) { } catch (OverlayManagerSettings.BadKeyException e) {
return false; return false;
} }
} }
boolean isPackageUpdatableOverlay(@NonNull final String packageName, final int userId) { private boolean isPackageUpdatableOverlay(@NonNull final String packageName, final int userId) {
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId); final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
if (overlayPackage == null || overlayPackage.isStaticOverlay) { if (overlayPackage == null || overlayPackage.isStaticOverlay) {
return false; return false;
@@ -346,18 +383,64 @@ final class OverlayManagerServiceImpl {
boolean setPriority(@NonNull final String packageName, boolean setPriority(@NonNull final String packageName,
@NonNull final String newParentPackageName, final int userId) { @NonNull final String newParentPackageName, final int userId) {
return isPackageUpdatableOverlay(packageName, userId) && if (DEBUG) {
mSettings.setPriority(packageName, newParentPackageName, userId); Slog.d(TAG, "setPriority packageName=" + packageName + " newParentPackageName="
+ newParentPackageName + " userId=" + userId);
}
if (!isPackageUpdatableOverlay(packageName, userId)) {
return false;
}
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
if (overlayPackage == null) {
return false;
}
if (mSettings.setPriority(packageName, newParentPackageName, userId)) {
mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
}
return true;
} }
boolean setHighestPriority(@NonNull final String packageName, final int userId) { boolean setHighestPriority(@NonNull final String packageName, final int userId) {
return isPackageUpdatableOverlay(packageName, userId) && if (DEBUG) {
mSettings.setHighestPriority(packageName, userId); Slog.d(TAG, "setHighestPriority packageName=" + packageName + " userId=" + userId);
}
if (!isPackageUpdatableOverlay(packageName, userId)) {
return false;
}
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
if (overlayPackage == null) {
return false;
}
if (mSettings.setHighestPriority(packageName, userId)) {
mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
}
return true;
} }
boolean setLowestPriority(@NonNull final String packageName, final int userId) { boolean setLowestPriority(@NonNull final String packageName, final int userId) {
return isPackageUpdatableOverlay(packageName, userId) && if (DEBUG) {
mSettings.setLowestPriority(packageName, userId); Slog.d(TAG, "setLowestPriority packageName=" + packageName + " userId=" + userId);
}
if (!isPackageUpdatableOverlay(packageName, userId)) {
return false;
}
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
if (overlayPackage == null) {
return false;
}
if (mSettings.setLowestPriority(packageName, userId)) {
mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
}
return true;
} }
void onDump(@NonNull final PrintWriter pw) { void onDump(@NonNull final PrintWriter pw) {
@@ -379,16 +462,19 @@ final class OverlayManagerServiceImpl {
return paths; return paths;
} }
private void updateState(@Nullable final PackageInfo targetPackage, /**
* Returns true if the settings/state was modified, false otherwise.
*/
private boolean updateState(@Nullable final PackageInfo targetPackage,
@NonNull final PackageInfo overlayPackage, final int userId) @NonNull final PackageInfo overlayPackage, final int userId)
throws OverlayManagerSettings.BadKeyException { throws OverlayManagerSettings.BadKeyException {
// Static RROs targeting to "android", ie framework-res.apk, are handled by native layers. // Static RROs targeting to "android", ie framework-res.apk, are handled by native layers.
if (targetPackage != null && if (targetPackage != null &&
!("android".equals(targetPackage.packageName) && overlayPackage.isStaticOverlay)) { !("android".equals(targetPackage.packageName) && overlayPackage.isStaticOverlay)) {
mIdmapManager.createIdmap(targetPackage, overlayPackage, userId); mIdmapManager.createIdmap(targetPackage, overlayPackage, userId);
} }
mSettings.setBaseCodePath(overlayPackage.packageName, userId, boolean modified = mSettings.setBaseCodePath(overlayPackage.packageName, userId,
overlayPackage.applicationInfo.getBaseCodePath()); overlayPackage.applicationInfo.getBaseCodePath());
final int currentState = mSettings.getState(overlayPackage.packageName, userId); final int currentState = mSettings.getState(overlayPackage.packageName, userId);
@@ -400,8 +486,9 @@ final class OverlayManagerServiceImpl {
OverlayInfo.stateToString(currentState), OverlayInfo.stateToString(currentState),
OverlayInfo.stateToString(newState))); OverlayInfo.stateToString(newState)));
} }
mSettings.setState(overlayPackage.packageName, userId, newState); modified |= mSettings.setState(overlayPackage.packageName, userId, newState);
} }
return modified;
} }
private int calculateNewState(@Nullable final PackageInfo targetPackage, private int calculateNewState(@Nullable final PackageInfo targetPackage,
@@ -441,10 +528,8 @@ final class OverlayManagerServiceImpl {
if (!mIdmapManager.idmapExists(oi)) { if (!mIdmapManager.idmapExists(oi)) {
return; return;
} }
final List<Integer> userIds = mSettings.getUsers(); final int[] userIds = mSettings.getUsers();
final int N = userIds.size(); for (int userId : userIds) {
for (int i = 0; i < N; i++) {
final int userId = userIds.get(i);
try { try {
final OverlayInfo tmp = mSettings.getOverlayInfo(oi.packageName, userId); final OverlayInfo tmp = mSettings.getOverlayInfo(oi.packageName, userId);
if (tmp != null && tmp.isEnabled()) { if (tmp != null && tmp.isEnabled()) {
@@ -458,6 +543,10 @@ final class OverlayManagerServiceImpl {
mIdmapManager.removeIdmap(oi, oi.userId); mIdmapManager.removeIdmap(oi, oi.userId);
} }
interface OverlayChangeListener {
void onOverlaysChanged(@NonNull String targetPackage, int userId);
}
interface PackageManagerHelper { interface PackageManagerHelper {
PackageInfo getPackageInfo(@NonNull String packageName, int userId); PackageInfo getPackageInfo(@NonNull String packageName, int userId);
boolean signaturesMatching(@NonNull String packageName1, @NonNull String packageName2, boolean signaturesMatching(@NonNull String packageName1, @NonNull String packageName2,

View File

@@ -16,17 +16,11 @@
package com.android.server.om; package com.android.server.om;
import static android.content.om.OverlayInfo.STATE_UNKNOWN;
import static com.android.server.om.OverlayManagerService.DEBUG;
import static com.android.server.om.OverlayManagerService.TAG;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.content.om.OverlayInfo; import android.content.om.OverlayInfo;
import android.util.AndroidRuntimeException; import android.util.AndroidRuntimeException;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.util.Slog;
import android.util.Xml; import android.util.Xml;
import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.FastXmlSerializer;
@@ -41,23 +35,28 @@ import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.stream.Collectors;
import java.util.stream.Stream;
/** /**
* Data structure representing the current state of all overlay packages in the * Data structure representing the current state of all overlay packages in the
* system. * system.
* *
* Modifications to the data are exposed through the ChangeListener interface. * Modifications to the data are signaled by returning true from any state mutating method.
* *
* @see ChangeListener
* @see OverlayManagerService * @see OverlayManagerService
*/ */
final class OverlayManagerSettings { final class OverlayManagerSettings {
private final List<ChangeListener> mListeners = new ArrayList<>(); /**
* All overlay data for all users and target packages is stored in this list.
* This keeps memory down, while increasing the cost of running queries or mutating the
* data. This is ok, since changing of overlays is very rare and has larger costs associated
* with it.
*
* The order of the items in the list is important, those with a lower index having a lower
* priority.
*/
private final ArrayList<SettingsItem> mItems = new ArrayList<>(); private final ArrayList<SettingsItem> mItems = new ArrayList<>();
void init(@NonNull final String packageName, final int userId, void init(@NonNull final String packageName, final int userId,
@@ -68,225 +67,176 @@ final class OverlayManagerSettings {
mItems.add(item); mItems.add(item);
} }
void remove(@NonNull final String packageName, final int userId) { /**
final SettingsItem item = select(packageName, userId); * Returns true if the settings were modified, false if they remain the same.
if (item == null) { */
return; boolean remove(@NonNull final String packageName, final int userId) {
final int idx = select(packageName, userId);
if (idx < 0) {
return false;
} }
final OverlayInfo oi = item.getOverlayInfo();
mItems.remove(item);
if (oi != null) {
notifyOverlayRemoved(oi);
}
}
boolean contains(@NonNull final String packageName, final int userId) { mItems.remove(idx);
return select(packageName, userId) != null; return true;
} }
OverlayInfo getOverlayInfo(@NonNull final String packageName, final int userId) OverlayInfo getOverlayInfo(@NonNull final String packageName, final int userId)
throws BadKeyException { throws BadKeyException {
final SettingsItem item = select(packageName, userId); final int idx = select(packageName, userId);
if (item == null) { if (idx < 0) {
throw new BadKeyException(packageName, userId); throw new BadKeyException(packageName, userId);
} }
return item.getOverlayInfo(); return mItems.get(idx).getOverlayInfo();
} }
String getTargetPackageName(@NonNull final String packageName, final int userId) /**
throws BadKeyException { * Returns true if the settings were modified, false if they remain the same.
final SettingsItem item = select(packageName, userId); */
if (item == null) { boolean setBaseCodePath(@NonNull final String packageName, final int userId,
throw new BadKeyException(packageName, userId);
}
return item.getTargetPackageName();
}
void setBaseCodePath(@NonNull final String packageName, final int userId,
@NonNull final String path) throws BadKeyException { @NonNull final String path) throws BadKeyException {
final SettingsItem item = select(packageName, userId); final int idx = select(packageName, userId);
if (item == null) { if (idx < 0) {
throw new BadKeyException(packageName, userId); throw new BadKeyException(packageName, userId);
} }
item.setBaseCodePath(path); return mItems.get(idx).setBaseCodePath(path);
notifySettingsChanged();
} }
boolean getEnabled(@NonNull final String packageName, final int userId) throws BadKeyException { boolean getEnabled(@NonNull final String packageName, final int userId) throws BadKeyException {
final SettingsItem item = select(packageName, userId); final int idx = select(packageName, userId);
if (item == null) { if (idx < 0) {
throw new BadKeyException(packageName, userId); throw new BadKeyException(packageName, userId);
} }
return item.isEnabled(); return mItems.get(idx).isEnabled();
} }
void setEnabled(@NonNull final String packageName, final int userId, final boolean enable) /**
* Returns true if the settings were modified, false if they remain the same.
*/
boolean setEnabled(@NonNull final String packageName, final int userId, final boolean enable)
throws BadKeyException { throws BadKeyException {
final SettingsItem item = select(packageName, userId); final int idx = select(packageName, userId);
if (item == null) { if (idx < 0) {
throw new BadKeyException(packageName, userId); throw new BadKeyException(packageName, userId);
} }
if (enable == item.isEnabled()) { return mItems.get(idx).setEnabled(enable);
return; // nothing to do
}
item.setEnabled(enable);
notifySettingsChanged();
} }
int getState(@NonNull final String packageName, final int userId) throws BadKeyException { int getState(@NonNull final String packageName, final int userId) throws BadKeyException {
final SettingsItem item = select(packageName, userId); final int idx = select(packageName, userId);
if (item == null) { if (idx < 0) {
throw new BadKeyException(packageName, userId); throw new BadKeyException(packageName, userId);
} }
return item.getState(); return mItems.get(idx).getState();
} }
void setState(@NonNull final String packageName, final int userId, final int state) /**
* Returns true if the settings were modified, false if they remain the same.
*/
boolean setState(@NonNull final String packageName, final int userId, final int state)
throws BadKeyException { throws BadKeyException {
final SettingsItem item = select(packageName, userId); final int idx = select(packageName, userId);
if (item == null) { if (idx < 0) {
throw new BadKeyException(packageName, userId); throw new BadKeyException(packageName, userId);
} }
final OverlayInfo previous = item.getOverlayInfo(); return mItems.get(idx).setState(state);
item.setState(state);
final OverlayInfo current = item.getOverlayInfo();
if (previous.state == STATE_UNKNOWN) {
notifyOverlayAdded(current);
notifySettingsChanged();
} else if (current.state != previous.state) {
notifyOverlayChanged(current, previous);
notifySettingsChanged();
}
} }
List<OverlayInfo> getOverlaysForTarget(@NonNull final String targetPackageName, List<OverlayInfo> getOverlaysForTarget(@NonNull final String targetPackageName,
final int userId) { final int userId) {
final List<SettingsItem> items = selectWhereTarget(targetPackageName, userId); return selectWhereTarget(targetPackageName, userId)
if (items.isEmpty()) { .map(SettingsItem::getOverlayInfo)
return Collections.emptyList(); .collect(Collectors.toList());
}
final List<OverlayInfo> out = new ArrayList<>(items.size());
final int N = items.size();
for (int i = 0; i < N; i++) {
final SettingsItem item = items.get(i);
out.add(item.getOverlayInfo());
}
return out;
} }
ArrayMap<String, List<OverlayInfo>> getOverlaysForUser(final int userId) { ArrayMap<String, List<OverlayInfo>> getOverlaysForUser(final int userId) {
final List<SettingsItem> items = selectWhereUser(userId); return selectWhereUser(userId)
if (items.isEmpty()) { .map(SettingsItem::getOverlayInfo)
return ArrayMap.EMPTY; .collect(Collectors.groupingBy(info -> info.targetPackageName, ArrayMap::new,
} Collectors.toList()));
final ArrayMap<String, List<OverlayInfo>> out = new ArrayMap<>(items.size());
final int N = items.size();
for (int i = 0; i < N; i++) {
final SettingsItem item = items.get(i);
final String targetPackageName = item.getTargetPackageName();
if (!out.containsKey(targetPackageName)) {
out.put(targetPackageName, new ArrayList<OverlayInfo>());
}
final List<OverlayInfo> overlays = out.get(targetPackageName);
overlays.add(item.getOverlayInfo());
}
return out;
} }
List<String> getTargetPackageNamesForUser(final int userId) { int[] getUsers() {
final List<SettingsItem> items = selectWhereUser(userId); return mItems.stream().mapToInt(SettingsItem::getUserId).distinct().toArray();
if (items.isEmpty()) {
return Collections.emptyList();
}
final List<String> out = new ArrayList<>();
final int N = items.size();
for (int i = 0; i < N; i++) {
final SettingsItem item = items.get(i);
final String targetPackageName = item.getTargetPackageName();
if (!out.contains(targetPackageName)) {
out.add(targetPackageName);
}
}
return out;
} }
List<Integer> getUsers() { /**
final ArrayList<Integer> users = new ArrayList<>(); * Returns true if the settings were modified, false if they remain the same.
final int N = mItems.size(); */
for (int i = 0; i < N; i++) { boolean removeUser(final int userId) {
boolean removed = false;
for (int i = 0; i < mItems.size(); i++) {
final SettingsItem item = mItems.get(i); final SettingsItem item = mItems.get(i);
if (!users.contains(item.userId)) { if (item.getUserId() == userId) {
users.add(item.userId); mItems.remove(i);
} removed = true;
} i--;
return users;
}
void removeUser(final int userId) {
final Iterator<SettingsItem> iter = mItems.iterator();
while (iter.hasNext()) {
final SettingsItem item = iter.next();
if (item.userId == userId) {
iter.remove();
} }
} }
return removed;
} }
/**
* Returns true if the settings were modified, false if they remain the same.
*/
boolean setPriority(@NonNull final String packageName, boolean setPriority(@NonNull final String packageName,
@NonNull final String newParentPackageName, final int userId) { @NonNull final String newParentPackageName, final int userId) {
if (packageName.equals(newParentPackageName)) { if (packageName.equals(newParentPackageName)) {
return false; return false;
} }
final SettingsItem rowToMove = select(packageName, userId); final int moveIdx = select(packageName, userId);
if (rowToMove == null) { if (moveIdx < 0) {
return false;
}
final SettingsItem newParentRow = select(newParentPackageName, userId);
if (newParentRow == null) {
return false;
}
if (!rowToMove.getTargetPackageName().equals(newParentRow.getTargetPackageName())) {
return false; return false;
} }
mItems.remove(rowToMove); final int parentIdx = select(newParentPackageName, userId);
final ListIterator<SettingsItem> iter = mItems.listIterator(); if (parentIdx < 0) {
while (iter.hasNext()) { return false;
final SettingsItem item = iter.next();
if (item.userId == userId && item.packageName.equals(newParentPackageName)) {
iter.add(rowToMove);
notifyOverlayPriorityChanged(rowToMove.getOverlayInfo());
notifySettingsChanged();
return true;
}
} }
Slog.wtf(TAG, "failed to find the parent item a second time"); final SettingsItem itemToMove = mItems.get(moveIdx);
return false;
// Make sure both packages are targeting the same package.
if (!itemToMove.getTargetPackageName().equals(
mItems.get(parentIdx).getTargetPackageName())) {
return false;
}
mItems.remove(moveIdx);
final int newParentIdx = select(newParentPackageName, userId);
mItems.add(newParentIdx, itemToMove);
return moveIdx != newParentIdx;
} }
/**
* Returns true if the settings were modified, false if they remain the same.
*/
boolean setLowestPriority(@NonNull final String packageName, final int userId) { boolean setLowestPriority(@NonNull final String packageName, final int userId) {
final SettingsItem item = select(packageName, userId); final int idx = select(packageName, userId);
if (item == null) { if (idx <= 0) {
// If the item doesn't exist or is already the lowest, don't change anything.
return false; return false;
} }
final SettingsItem item = mItems.get(idx);
mItems.remove(item); mItems.remove(item);
mItems.add(0, item); mItems.add(0, item);
notifyOverlayPriorityChanged(item.getOverlayInfo());
notifySettingsChanged();
return true; return true;
} }
/**
* Returns true if the settings were modified, false if they remain the same.
*/
boolean setHighestPriority(@NonNull final String packageName, final int userId) { boolean setHighestPriority(@NonNull final String packageName, final int userId) {
final SettingsItem item = select(packageName, userId); final int idx = select(packageName, userId);
if (item == null) {
// If the item doesn't exist or is already the highest, don't change anything.
if (idx < 0 || idx == mItems.size() - 1) {
return false; return false;
} }
mItems.remove(item);
final SettingsItem item = mItems.get(idx);
mItems.remove(idx);
mItems.add(item); mItems.add(item);
notifyOverlayPriorityChanged(item.getOverlayInfo());
notifySettingsChanged();
return true; return true;
} }
@@ -296,11 +246,6 @@ final class OverlayManagerSettings {
void dump(@NonNull final PrintWriter pw) { void dump(@NonNull final PrintWriter pw) {
pw.println("Settings"); pw.println("Settings");
dumpItems(pw);
dumpListeners(pw);
}
private void dumpItems(@NonNull final PrintWriter pw) {
pw.println(TAB1 + "Items"); pw.println(TAB1 + "Items");
if (mItems.isEmpty()) { if (mItems.isEmpty()) {
@@ -312,34 +257,18 @@ final class OverlayManagerSettings {
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
final SettingsItem item = mItems.get(i); final SettingsItem item = mItems.get(i);
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
sb.append(TAB2 + item.packageName + ":" + item.userId + " {\n"); sb.append(TAB2 + item.mPackageName + ":" + item.getUserId() + " {\n");
sb.append(TAB3 + "packageName.......: " + item.packageName + "\n"); sb.append(TAB3 + "mPackageName.......: " + item.mPackageName + "\n");
sb.append(TAB3 + "userId............: " + item.userId + "\n"); sb.append(TAB3 + "mUserId............: " + item.getUserId() + "\n");
sb.append(TAB3 + "targetPackageName.: " + item.getTargetPackageName() + "\n"); sb.append(TAB3 + "mTargetPackageName.: " + item.getTargetPackageName() + "\n");
sb.append(TAB3 + "baseCodePath......: " + item.getBaseCodePath() + "\n"); sb.append(TAB3 + "mBaseCodePath......: " + item.getBaseCodePath() + "\n");
sb.append(TAB3 + "state.............: " + OverlayInfo.stateToString(item.getState()) + "\n"); sb.append(TAB3 + "mState.............: " + OverlayInfo.stateToString(item.getState()) + "\n");
sb.append(TAB3 + "isEnabled.........: " + item.isEnabled() + "\n"); sb.append(TAB3 + "mIsEnabled.........: " + item.isEnabled() + "\n");
sb.append(TAB2 + "}"); sb.append(TAB2 + "}");
pw.println(sb.toString()); pw.println(sb.toString());
} }
} }
private void dumpListeners(@NonNull final PrintWriter pw) {
pw.println(TAB1 + "Change listeners");
if (mListeners.isEmpty()) {
pw.println(TAB2 + "<none>");
return;
}
final int N = mListeners.size();
for (int i = 0; i < N; i++) {
final ChangeListener ch = mListeners.get(i);
pw.println(TAB2 + ch);
}
}
void restore(@NonNull final InputStream is) throws IOException, XmlPullParserException { void restore(@NonNull final InputStream is) throws IOException, XmlPullParserException {
Serializer.restore(mItems, is); Serializer.restore(mItems, is);
} }
@@ -434,127 +363,122 @@ final class OverlayManagerSettings {
private static void persistRow(@NonNull final FastXmlSerializer xml, private static void persistRow(@NonNull final FastXmlSerializer xml,
@NonNull final SettingsItem item) throws IOException { @NonNull final SettingsItem item) throws IOException {
xml.startTag(null, TAG_ITEM); xml.startTag(null, TAG_ITEM);
XmlUtils.writeStringAttribute(xml, ATTR_PACKAGE_NAME, item.packageName); XmlUtils.writeStringAttribute(xml, ATTR_PACKAGE_NAME, item.mPackageName);
XmlUtils.writeIntAttribute(xml, ATTR_USER_ID, item.userId); XmlUtils.writeIntAttribute(xml, ATTR_USER_ID, item.mUserId);
XmlUtils.writeStringAttribute(xml, ATTR_TARGET_PACKAGE_NAME, item.targetPackageName); XmlUtils.writeStringAttribute(xml, ATTR_TARGET_PACKAGE_NAME, item.mTargetPackageName);
XmlUtils.writeStringAttribute(xml, ATTR_BASE_CODE_PATH, item.baseCodePath); XmlUtils.writeStringAttribute(xml, ATTR_BASE_CODE_PATH, item.mBaseCodePath);
XmlUtils.writeIntAttribute(xml, ATTR_STATE, item.state); XmlUtils.writeIntAttribute(xml, ATTR_STATE, item.mState);
XmlUtils.writeBooleanAttribute(xml, ATTR_IS_ENABLED, item.isEnabled); XmlUtils.writeBooleanAttribute(xml, ATTR_IS_ENABLED, item.mIsEnabled);
xml.endTag(null, TAG_ITEM); xml.endTag(null, TAG_ITEM);
} }
} }
private static final class SettingsItem { private static final class SettingsItem {
private final int userId; private final int mUserId;
private final String packageName; private final String mPackageName;
private final String targetPackageName; private final String mTargetPackageName;
private String baseCodePath; private String mBaseCodePath;
private int state; private int mState;
private boolean isEnabled; private boolean mIsEnabled;
private OverlayInfo cache; private OverlayInfo mCache;
SettingsItem(@NonNull final String packageName, final int userId, SettingsItem(@NonNull final String packageName, final int userId,
@NonNull final String targetPackageName, @NonNull final String baseCodePath, @NonNull final String targetPackageName, @NonNull final String baseCodePath,
final int state, final boolean isEnabled) { final int state, final boolean isEnabled) {
this.packageName = packageName; mPackageName = packageName;
this.userId = userId; mUserId = userId;
this.targetPackageName = targetPackageName; mTargetPackageName = targetPackageName;
this.baseCodePath = baseCodePath; mBaseCodePath = baseCodePath;
this.state = state; mState = state;
this.isEnabled = isEnabled; mIsEnabled = isEnabled;
cache = null; mCache = null;
} }
SettingsItem(@NonNull final String packageName, final int userId, SettingsItem(@NonNull final String packageName, final int userId,
@NonNull final String targetPackageName, @NonNull final String baseCodePath) { @NonNull final String targetPackageName, @NonNull final String baseCodePath) {
this(packageName, userId, targetPackageName, baseCodePath, STATE_UNKNOWN, this(packageName, userId, targetPackageName, baseCodePath, OverlayInfo.STATE_UNKNOWN,
false); false);
} }
private String getTargetPackageName() { private String getTargetPackageName() {
return targetPackageName; return mTargetPackageName;
}
private int getUserId() {
return mUserId;
} }
private String getBaseCodePath() { private String getBaseCodePath() {
return baseCodePath; return mBaseCodePath;
} }
private void setBaseCodePath(@NonNull final String path) { private boolean setBaseCodePath(@NonNull final String path) {
if (!baseCodePath.equals(path)) { if (!mBaseCodePath.equals(path)) {
baseCodePath = path; mBaseCodePath = path;
invalidateCache(); invalidateCache();
return true;
} }
return false;
} }
private int getState() { private int getState() {
return state; return mState;
} }
private void setState(final int state) { private boolean setState(final int state) {
if (this.state != state) { if (mState != state) {
this.state = state; mState = state;
invalidateCache(); invalidateCache();
return true;
} }
return false;
} }
private boolean isEnabled() { private boolean isEnabled() {
return isEnabled; return mIsEnabled;
} }
private void setEnabled(final boolean enable) { private boolean setEnabled(final boolean enable) {
if (isEnabled != enable) { if (mIsEnabled != enable) {
isEnabled = enable; mIsEnabled = enable;
invalidateCache(); invalidateCache();
return true;
} }
return false;
} }
private OverlayInfo getOverlayInfo() { private OverlayInfo getOverlayInfo() {
if (cache == null) { if (mCache == null) {
cache = new OverlayInfo(packageName, targetPackageName, baseCodePath, mCache = new OverlayInfo(mPackageName, mTargetPackageName, mBaseCodePath, mState,
state, userId); mUserId);
} }
return cache; return mCache;
} }
private void invalidateCache() { private void invalidateCache() {
cache = null; mCache = null;
} }
} }
private SettingsItem select(@NonNull final String packageName, final int userId) { private int select(@NonNull final String packageName, final int userId) {
final int N = mItems.size(); final int N = mItems.size();
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
final SettingsItem item = mItems.get(i); final SettingsItem item = mItems.get(i);
if (item.userId == userId && item.packageName.equals(packageName)) { if (item.mUserId == userId && item.mPackageName.equals(packageName)) {
return item; return i;
} }
} }
return null; return -1;
} }
private List<SettingsItem> selectWhereUser(final int userId) { private Stream<SettingsItem> selectWhereUser(final int userId) {
final ArrayList<SettingsItem> items = new ArrayList<>(); return mItems.stream().filter(item -> item.mUserId == userId);
final int N = mItems.size();
for (int i = 0; i < N; i++) {
final SettingsItem item = mItems.get(i);
if (item.userId == userId) {
items.add(item);
}
}
return items;
} }
private List<SettingsItem> selectWhereTarget(@NonNull final String targetPackageName, private Stream<SettingsItem> selectWhereTarget(@NonNull final String targetPackageName,
final int userId) { final int userId) {
final ArrayList<SettingsItem> items = new ArrayList<>(); return selectWhereUser(userId)
final int N = mItems.size(); .filter(item -> item.getTargetPackageName().equals(targetPackageName));
for (int i = 0; i < N; i++) {
final SettingsItem item = mItems.get(i);
if (item.userId == userId && item.getTargetPackageName().equals(targetPackageName)) {
items.add(item);
}
}
return items;
} }
private void assertNotNull(@Nullable final Object o) { private void assertNotNull(@Nullable final Object o) {
@@ -563,79 +487,9 @@ final class OverlayManagerSettings {
} }
} }
void addChangeListener(@NonNull final ChangeListener listener) {
mListeners.add(listener);
}
void removeChangeListener(@NonNull final ChangeListener listener) {
mListeners.remove(listener);
}
private void notifySettingsChanged() {
final int N = mListeners.size();
for (int i = 0; i < N; i++) {
final ChangeListener listener = mListeners.get(i);
listener.onSettingsChanged();
}
}
private void notifyOverlayAdded(@NonNull final OverlayInfo oi) {
if (DEBUG) {
assertNotNull(oi);
}
final int N = mListeners.size();
for (int i = 0; i < N; i++) {
final ChangeListener listener = mListeners.get(i);
listener.onOverlayAdded(oi);
}
}
private void notifyOverlayRemoved(@NonNull final OverlayInfo oi) {
if (DEBUG) {
assertNotNull(oi);
}
final int N = mListeners.size();
for (int i = 0; i < N; i++) {
final ChangeListener listener = mListeners.get(i);
listener.onOverlayRemoved(oi);
}
}
private void notifyOverlayChanged(@NonNull final OverlayInfo oi,
@NonNull final OverlayInfo oldOi) {
if (DEBUG) {
assertNotNull(oi);
assertNotNull(oldOi);
}
final int N = mListeners.size();
for (int i = 0; i < N; i++) {
final ChangeListener listener = mListeners.get(i);
listener.onOverlayChanged(oi, oldOi);
}
}
private void notifyOverlayPriorityChanged(@NonNull final OverlayInfo oi) {
if (DEBUG) {
assertNotNull(oi);
}
final int N = mListeners.size();
for (int i = 0; i < N; i++) {
final ChangeListener listener = mListeners.get(i);
listener.onOverlayPriorityChanged(oi);
}
}
interface ChangeListener {
void onSettingsChanged();
void onOverlayAdded(@NonNull OverlayInfo oi);
void onOverlayRemoved(@NonNull OverlayInfo oi);
void onOverlayChanged(@NonNull OverlayInfo oi, @NonNull OverlayInfo oldOi);
void onOverlayPriorityChanged(@NonNull OverlayInfo oi);
}
static final class BadKeyException extends RuntimeException { static final class BadKeyException extends RuntimeException {
BadKeyException(@NonNull final String packageName, final int userId) { BadKeyException(@NonNull final String packageName, final int userId) {
super("Bad key packageName=" + packageName + " userId=" + userId); super("Bad key mPackageName=" + packageName + " mUserId=" + userId);
} }
} }
} }