Merge "OverlayManagerService: Make broadcasts/updates explicit" into oc-dev
am: ec8f353668
Change-Id: Ied4fc0b2fe79c69e6fd1b8677a5d615300119b39
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user