Merge "Apply/remove overrides for a package when it's added/changed/removed." into sc-v2-dev
This commit is contained in:
@@ -16,6 +16,9 @@
|
||||
|
||||
package com.android.server.compat.overrides;
|
||||
|
||||
import static android.content.Intent.ACTION_PACKAGE_ADDED;
|
||||
import static android.content.Intent.ACTION_PACKAGE_CHANGED;
|
||||
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
|
||||
import static android.content.pm.PackageManager.MATCH_ANY_USER;
|
||||
import static android.provider.DeviceConfig.NAMESPACE_APP_COMPAT_OVERRIDES;
|
||||
|
||||
@@ -24,11 +27,16 @@ import static com.android.server.compat.overrides.AppCompatOverridesParser.FLAG_
|
||||
|
||||
import static java.util.Collections.emptySet;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.compat.PackageOverride;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.provider.DeviceConfig;
|
||||
@@ -67,8 +75,9 @@ public final class AppCompatOverridesService {
|
||||
private final PackageManager mPackageManager;
|
||||
private final IPlatformCompat mPlatformCompat;
|
||||
private final List<String> mSupportedNamespaces;
|
||||
private final List<DeviceConfigListener> mDeviceConfigListeners;
|
||||
private final AppCompatOverridesParser mOverridesParser;
|
||||
private final PackageReceiver mPackageReceiver;
|
||||
private final List<DeviceConfigListener> mDeviceConfigListeners;
|
||||
|
||||
private AppCompatOverridesService(Context context) {
|
||||
this(context, IPlatformCompat.Stub.asInterface(
|
||||
@@ -82,31 +91,42 @@ public final class AppCompatOverridesService {
|
||||
mPackageManager = mContext.getPackageManager();
|
||||
mPlatformCompat = platformCompat;
|
||||
mSupportedNamespaces = supportedNamespaces;
|
||||
mDeviceConfigListeners = new ArrayList<>();
|
||||
mOverridesParser = new AppCompatOverridesParser(mPackageManager);
|
||||
mPackageReceiver = new PackageReceiver(mContext);
|
||||
mDeviceConfigListeners = new ArrayList<>();
|
||||
for (String namespace : mSupportedNamespaces) {
|
||||
mDeviceConfigListeners.add(new DeviceConfigListener(mContext, namespace));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finalize() {
|
||||
unregisterDeviceConfigListeners();
|
||||
unregisterPackageReceiver();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void registerDeviceConfigListeners() {
|
||||
for (String namespace : mSupportedNamespaces) {
|
||||
DeviceConfigListener listener = new DeviceConfigListener(namespace);
|
||||
DeviceConfig.addOnPropertiesChangedListener(namespace, mContext.getMainExecutor(),
|
||||
listener);
|
||||
mDeviceConfigListeners.add(listener);
|
||||
for (DeviceConfigListener listener : mDeviceConfigListeners) {
|
||||
listener.register();
|
||||
}
|
||||
}
|
||||
|
||||
private void unregisterDeviceConfigListeners() {
|
||||
for (DeviceConfigListener listener : mDeviceConfigListeners) {
|
||||
DeviceConfig.removeOnPropertiesChangedListener(listener);
|
||||
listener.unregister();
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void registerPackageReceiver() {
|
||||
mPackageReceiver.register();
|
||||
}
|
||||
|
||||
private void unregisterPackageReceiver() {
|
||||
mPackageReceiver.unregister();
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #applyOverrides(Properties, Map)} except all properties of the given {@code
|
||||
* namespace} are fetched via {@link DeviceConfig#getProperties}.
|
||||
@@ -139,6 +159,25 @@ public final class AppCompatOverridesService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies all overrides in all supported namespaces for the given {@code packageName}.
|
||||
*/
|
||||
private void applyAllPackageOverrides(String packageName) {
|
||||
Long versionCode = getVersionCodeOrNull(packageName);
|
||||
if (versionCode == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (String namespace : mSupportedNamespaces) {
|
||||
// We apply overrides for each namespace separately so that if there is a failure for
|
||||
// one namespace, the other namespaces won't be affected.
|
||||
applyPackageOverrides(
|
||||
DeviceConfig.getString(namespace, packageName, /* defaultValue= */ ""),
|
||||
packageName, versionCode,
|
||||
getOverridesToRemove(namespace).getOrDefault(packageName, emptySet()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link AppCompatOverridesParser#parsePackageOverrides} on the given arguments, adds the
|
||||
* resulting {@link PackageOverrides#overridesToAdd} via {@link
|
||||
@@ -154,6 +193,24 @@ public final class AppCompatOverridesService {
|
||||
removePackageOverrides(packageName, packageOverrides.overridesToRemove);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all owned overrides in all supported namespaces for the given {@code packageName}.
|
||||
*
|
||||
* <p>If a certain namespace doesn't have a package override flag for the given {@code
|
||||
* packageName}, that namespace is skipped.</p>
|
||||
*/
|
||||
private void removeAllPackageOverrides(String packageName) {
|
||||
for (String namespace : mSupportedNamespaces) {
|
||||
if (DeviceConfig.getString(namespace, packageName, /* defaultValue= */ "").isEmpty()) {
|
||||
// No overrides for this package in this namespace.
|
||||
continue;
|
||||
}
|
||||
// We remove overrides for each namespace separately so that if there is a failure for
|
||||
// one namespace, the other namespaces won't be affected.
|
||||
removePackageOverrides(packageName, getOwnedChangeIds(namespace));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link IPlatformCompat#removeOverridesOnReleaseBuilds} on each package name and
|
||||
* respective change IDs in {@code overridesToRemove}.
|
||||
@@ -211,6 +268,10 @@ public final class AppCompatOverridesService {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInstalledForAnyUser(String packageName) {
|
||||
return getVersionCodeOrNull(packageName) != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Long getVersionCodeOrNull(String packageName) {
|
||||
try {
|
||||
@@ -218,7 +279,7 @@ public final class AppCompatOverridesService {
|
||||
MATCH_ANY_USER);
|
||||
return applicationInfo.longVersionCode;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
// Package isn't installed yet.
|
||||
// Package isn't installed for any user.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -239,6 +300,7 @@ public final class AppCompatOverridesService {
|
||||
public void onStart() {
|
||||
mService = new AppCompatOverridesService(getContext());
|
||||
mService.registerDeviceConfigListeners();
|
||||
mService.registerPackageReceiver();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,12 +309,23 @@ public final class AppCompatOverridesService {
|
||||
* namespace and adds/removes overrides according to the changed flags.
|
||||
*/
|
||||
private final class DeviceConfigListener implements DeviceConfig.OnPropertiesChangedListener {
|
||||
private final Context mContext;
|
||||
private final String mNamespace;
|
||||
|
||||
private DeviceConfigListener(String namespace) {
|
||||
private DeviceConfigListener(Context context, String namespace) {
|
||||
mContext = context;
|
||||
mNamespace = namespace;
|
||||
}
|
||||
|
||||
private void register() {
|
||||
DeviceConfig.addOnPropertiesChangedListener(mNamespace, mContext.getMainExecutor(),
|
||||
this);
|
||||
}
|
||||
|
||||
private void unregister() {
|
||||
DeviceConfig.removeOnPropertiesChangedListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPropertiesChanged(Properties properties) {
|
||||
boolean removeOverridesFlagChanged = properties.getKeyset().contains(
|
||||
@@ -276,4 +349,60 @@ public final class AppCompatOverridesService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link BroadcastReceiver} that listens on package added/changed/removed events and
|
||||
* adds/removes overrides according to the corresponding Device Config flags.
|
||||
*/
|
||||
private final class PackageReceiver extends BroadcastReceiver {
|
||||
private final Context mContext;
|
||||
private final IntentFilter mIntentFilter;
|
||||
|
||||
private PackageReceiver(Context context) {
|
||||
mContext = context;
|
||||
mIntentFilter = new IntentFilter();
|
||||
mIntentFilter.addAction(ACTION_PACKAGE_ADDED);
|
||||
mIntentFilter.addAction(ACTION_PACKAGE_CHANGED);
|
||||
mIntentFilter.addAction(ACTION_PACKAGE_REMOVED);
|
||||
mIntentFilter.addDataScheme("package");
|
||||
}
|
||||
|
||||
private void register() {
|
||||
mContext.registerReceiverForAllUsers(this, mIntentFilter, /* broadcastPermission= */
|
||||
null, /* scheduler= */ null);
|
||||
}
|
||||
|
||||
private void unregister() {
|
||||
mContext.unregisterReceiver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
|
||||
Uri data = intent.getData();
|
||||
if (data == null) {
|
||||
Slog.w(TAG, "Failed to get package name in package receiver");
|
||||
return;
|
||||
}
|
||||
String packageName = data.getSchemeSpecificPart();
|
||||
String action = intent.getAction();
|
||||
if (action == null) {
|
||||
Slog.w(TAG, "Failed to get action in package receiver");
|
||||
return;
|
||||
}
|
||||
switch (action) {
|
||||
case ACTION_PACKAGE_ADDED:
|
||||
case ACTION_PACKAGE_CHANGED:
|
||||
applyAllPackageOverrides(packageName);
|
||||
break;
|
||||
case ACTION_PACKAGE_REMOVED:
|
||||
if (!isInstalledForAnyUser(packageName)) {
|
||||
removeAllPackageOverrides(packageName);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Slog.w(TAG, "Unsupported action in package receiver: " + action);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
|
||||
package com.android.server.compat.overrides;
|
||||
|
||||
import static android.content.Intent.ACTION_PACKAGE_ADDED;
|
||||
import static android.content.Intent.ACTION_PACKAGE_CHANGED;
|
||||
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
|
||||
import static android.content.Intent.ACTION_USER_SWITCHED;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
|
||||
import static com.android.server.compat.overrides.AppCompatOverridesParser.FLAG_OWNED_CHANGE_IDS;
|
||||
import static com.android.server.compat.overrides.AppCompatOverridesParser.FLAG_REMOVE_OVERRIDES;
|
||||
@@ -24,17 +29,25 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.compat.PackageOverride;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.RemoteException;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.provider.DeviceConfig;
|
||||
@@ -73,7 +86,10 @@ import java.util.concurrent.Executor;
|
||||
@Presubmit
|
||||
public class AppCompatOverridesServiceTest {
|
||||
private static final String NAMESPACE_1 = "namespace_1";
|
||||
private static final List<String> SUPPORTED_NAMESPACES = Arrays.asList(NAMESPACE_1);
|
||||
private static final String NAMESPACE_2 = "namespace_2";
|
||||
private static final String NAMESPACE_3 = "namespace_3";
|
||||
private static final List<String> SUPPORTED_NAMESPACES = Arrays.asList(NAMESPACE_1,
|
||||
NAMESPACE_2, NAMESPACE_3);
|
||||
|
||||
private static final String PACKAGE_1 = "com.android.test1";
|
||||
private static final String PACKAGE_2 = "com.android.test2";
|
||||
@@ -82,6 +98,7 @@ public class AppCompatOverridesServiceTest {
|
||||
private static final String PACKAGE_5 = "com.android.test5";
|
||||
|
||||
private MockContext mMockContext;
|
||||
private BroadcastReceiver mPackageReceiver;
|
||||
private AppCompatOverridesService mService;
|
||||
|
||||
@Mock
|
||||
@@ -112,6 +129,15 @@ public class AppCompatOverridesServiceTest {
|
||||
// Run on current thread
|
||||
return Runnable::run;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Intent registerReceiverForAllUsers(@Nullable BroadcastReceiver receiver,
|
||||
@NonNull IntentFilter filter, @Nullable String broadcastPermission,
|
||||
@Nullable Handler scheduler) {
|
||||
mPackageReceiver = receiver;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
@@ -120,6 +146,8 @@ public class AppCompatOverridesServiceTest {
|
||||
InstrumentationRegistry.getInstrumentation().getTargetContext());
|
||||
mService = new AppCompatOverridesService(mMockContext, mPlatformCompat,
|
||||
SUPPORTED_NAMESPACES);
|
||||
mService.registerPackageReceiver();
|
||||
assertThat(mPackageReceiver).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -361,6 +389,282 @@ public class AppCompatOverridesServiceTest {
|
||||
any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_4));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void packageReceiver_packageAddedIntentDataIsNull_doesNothing() throws Exception {
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
|
||||
.setString(PACKAGE_1, "101:::true").build());
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
|
||||
.setString(PACKAGE_1, "201:::true").build());
|
||||
mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
|
||||
|
||||
mPackageReceiver.onReceive(mMockContext, new Intent(ACTION_PACKAGE_ADDED));
|
||||
|
||||
verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
|
||||
any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
|
||||
verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
|
||||
any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void packageReceiver_actionIsNull_doesNothing() throws Exception {
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
|
||||
.setString(PACKAGE_1, "101:::true").build());
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
|
||||
.setString(PACKAGE_1, "201:::true").build());
|
||||
mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
|
||||
|
||||
mPackageReceiver.onReceive(mMockContext,
|
||||
createPackageIntent(PACKAGE_1, /* action= */ null));
|
||||
|
||||
verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
|
||||
any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
|
||||
verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
|
||||
any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void packageReceiver_unsupportedAction_doesNothing() throws Exception {
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
|
||||
.setString(PACKAGE_1, "101:::true").build());
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
|
||||
.setString(PACKAGE_1, "201:::true").build());
|
||||
mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
|
||||
|
||||
mPackageReceiver.onReceive(mMockContext,
|
||||
createPackageIntent(PACKAGE_1, ACTION_USER_SWITCHED));
|
||||
|
||||
verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
|
||||
any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
|
||||
verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
|
||||
any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void packageReceiver_packageAddedIntentPackageNotInstalled_doesNothing()
|
||||
throws Exception {
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
|
||||
.setString(PACKAGE_1, "101:::true").build());
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
|
||||
.setString(PACKAGE_1, "201:::true").build());
|
||||
mockGetApplicationInfoNotInstalled(PACKAGE_1);
|
||||
|
||||
mPackageReceiver.onReceive(mMockContext,
|
||||
createPackageIntent(PACKAGE_1, ACTION_PACKAGE_ADDED));
|
||||
|
||||
verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
|
||||
any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
|
||||
verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
|
||||
any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void packageReceiver_packageAddedIntentNoOverridesForPackage_doesNothing()
|
||||
throws Exception {
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
|
||||
.setString(PACKAGE_2, "101:::true").build());
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
|
||||
.setString(PACKAGE_3, "201:::true").build());
|
||||
mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
|
||||
|
||||
mPackageReceiver.onReceive(mMockContext,
|
||||
createPackageIntent(PACKAGE_1, ACTION_PACKAGE_ADDED));
|
||||
|
||||
verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
|
||||
any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
|
||||
verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
|
||||
any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void packageReceiver_packageAddedIntent_appliesOverridesFromAllNamespaces()
|
||||
throws Exception {
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
|
||||
.setString(PACKAGE_1, "101:::true,103:::")
|
||||
.setString(PACKAGE_2, "102:::false").build());
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
|
||||
.setString(PACKAGE_3, "201:::false").build());
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3)
|
||||
.setString(PACKAGE_1, "301:::true,302:::false")
|
||||
.setString(PACKAGE_2, "302:::false").build());
|
||||
mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
|
||||
|
||||
mPackageReceiver.onReceive(mMockContext,
|
||||
createPackageIntent(PACKAGE_1, ACTION_PACKAGE_ADDED));
|
||||
|
||||
verify(mPlatformCompat, times(2)).putOverridesOnReleaseBuilds(
|
||||
mOverridesToAddConfigCaptor.capture(), eq(PACKAGE_1));
|
||||
verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
|
||||
mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
|
||||
List<CompatibilityOverrideConfig> configs = mOverridesToAddConfigCaptor.getAllValues();
|
||||
assertThat(configs.get(0).overrides.keySet()).containsExactly(101L);
|
||||
assertThat(configs.get(1).overrides.keySet()).containsExactly(301L, 302L);
|
||||
assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(103L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void packageReceiver_packageChangedIntent_appliesOverrides()
|
||||
throws Exception {
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
|
||||
.setString(PACKAGE_1, "101:::true,103:::").build());
|
||||
mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
|
||||
|
||||
mPackageReceiver.onReceive(mMockContext,
|
||||
createPackageIntent(PACKAGE_1, ACTION_PACKAGE_CHANGED));
|
||||
|
||||
verify(mPlatformCompat).putOverridesOnReleaseBuilds(
|
||||
mOverridesToAddConfigCaptor.capture(), eq(PACKAGE_1));
|
||||
verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
|
||||
mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
|
||||
assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(101L);
|
||||
assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(103L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void packageReceiver_packageAddedIntentRemoveOverridesSetForSomeNamespaces_skipsIds()
|
||||
throws Exception {
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
|
||||
.setString(FLAG_REMOVE_OVERRIDES, PACKAGE_1 + "=103," + PACKAGE_2 + "=101")
|
||||
.setString(PACKAGE_1, "101:::true,103:::")
|
||||
.setString(PACKAGE_2, "102:::false").build());
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
|
||||
.setString(PACKAGE_1, "201:::false").build());
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3)
|
||||
.setString(FLAG_REMOVE_OVERRIDES, PACKAGE_1 + "=301," + PACKAGE_3 + "=302")
|
||||
.setString(PACKAGE_1, "301:::true,302:::false,303:::")
|
||||
.setString(PACKAGE_3, "302:::false").build());
|
||||
mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
|
||||
|
||||
mPackageReceiver.onReceive(mMockContext,
|
||||
createPackageIntent(PACKAGE_1, ACTION_PACKAGE_ADDED));
|
||||
|
||||
verify(mPlatformCompat, times(3)).putOverridesOnReleaseBuilds(
|
||||
mOverridesToAddConfigCaptor.capture(), eq(PACKAGE_1));
|
||||
verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
|
||||
mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
|
||||
List<CompatibilityOverrideConfig> configs = mOverridesToAddConfigCaptor.getAllValues();
|
||||
assertThat(configs.get(0).overrides.keySet()).containsExactly(101L);
|
||||
assertThat(configs.get(1).overrides.keySet()).containsExactly(201L);
|
||||
assertThat(configs.get(2).overrides.keySet()).containsExactly(302L);
|
||||
assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(303L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void packageReceiver_packageRemovedIntentNoOverridesForPackage_doesNothing()
|
||||
throws Exception {
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
|
||||
.setString(FLAG_OWNED_CHANGE_IDS, "101,102")
|
||||
.setString(PACKAGE_2, "101:::true").build());
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
|
||||
.setString(FLAG_OWNED_CHANGE_IDS, "201,202")
|
||||
.setString(PACKAGE_3, "201:::true").build());
|
||||
mockGetApplicationInfoNotInstalled(PACKAGE_1);
|
||||
|
||||
mPackageReceiver.onReceive(mMockContext,
|
||||
createPackageIntent(PACKAGE_1, ACTION_PACKAGE_REMOVED));
|
||||
|
||||
verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
|
||||
any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
|
||||
verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
|
||||
any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void packageReceiver_packageRemovedIntentPackageInstalledForAnotherUser_doesNothing()
|
||||
throws Exception {
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
|
||||
.setString(FLAG_OWNED_CHANGE_IDS, "101,102,103")
|
||||
.setString(PACKAGE_1, "101:::true,103:::").build());
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
|
||||
.setString(FLAG_OWNED_CHANGE_IDS, "201,202")
|
||||
.setString(PACKAGE_1, "202:::false").build());
|
||||
mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
|
||||
|
||||
mPackageReceiver.onReceive(mMockContext,
|
||||
createPackageIntent(PACKAGE_1, ACTION_PACKAGE_REMOVED));
|
||||
|
||||
verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
|
||||
any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
|
||||
verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
|
||||
any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void packageReceiver_packageRemovedIntent_removesOwnedOverridesForNamespacesWithPackage()
|
||||
throws Exception {
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
|
||||
.setString(FLAG_OWNED_CHANGE_IDS, "101,102,103")
|
||||
.setString(PACKAGE_1, "101:::true,103:::")
|
||||
.setString(PACKAGE_2, "102:::false").build());
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
|
||||
.setString(FLAG_OWNED_CHANGE_IDS, "201")
|
||||
.setString(PACKAGE_3, "201:::false").build());
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3)
|
||||
.setString(FLAG_OWNED_CHANGE_IDS, "301,302")
|
||||
.setString(PACKAGE_1, "302:::")
|
||||
.setString(PACKAGE_2, "301:::true").build());
|
||||
mockGetApplicationInfoNotInstalled(PACKAGE_1);
|
||||
|
||||
mPackageReceiver.onReceive(mMockContext,
|
||||
createPackageIntent(PACKAGE_1, ACTION_PACKAGE_REMOVED));
|
||||
|
||||
verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
|
||||
any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
|
||||
verify(mPlatformCompat, times(2)).removeOverridesOnReleaseBuilds(
|
||||
mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
|
||||
List<CompatibilityOverridesToRemoveConfig> configs =
|
||||
mOverridesToRemoveConfigCaptor.getAllValues();
|
||||
assertThat(configs.get(0).changeIds).containsExactly(101L, 102L, 103L);
|
||||
assertThat(configs.get(1).changeIds).containsExactly(301L, 302L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void packageReceiver_packageRemovedIntentNoOwnedIdsForSomeNamespace_skipsNamespace()
|
||||
throws Exception {
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
|
||||
.setString(FLAG_OWNED_CHANGE_IDS, "101,102")
|
||||
.setString(PACKAGE_1, "101:::true").build());
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
|
||||
.setString(PACKAGE_1, "201:::false").build());
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3)
|
||||
.setString(FLAG_OWNED_CHANGE_IDS, "301")
|
||||
.setString(PACKAGE_1, "301:::true").build());
|
||||
mockGetApplicationInfoNotInstalled(PACKAGE_1);
|
||||
|
||||
mPackageReceiver.onReceive(mMockContext,
|
||||
createPackageIntent(PACKAGE_1, ACTION_PACKAGE_REMOVED));
|
||||
|
||||
verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
|
||||
any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
|
||||
verify(mPlatformCompat, times(2)).removeOverridesOnReleaseBuilds(
|
||||
mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
|
||||
List<CompatibilityOverridesToRemoveConfig> configs =
|
||||
mOverridesToRemoveConfigCaptor.getAllValues();
|
||||
assertThat(configs.get(0).changeIds).containsExactly(101L, 102L);
|
||||
assertThat(configs.get(1).changeIds).containsExactly(301L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void packageReceiver_platformCompatThrowsExceptionForSomeNamespace_skipsFailedCall()
|
||||
throws Exception {
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
|
||||
.setString(PACKAGE_1, "101:::true").build());
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
|
||||
.setString(PACKAGE_1, "201:::false").build());
|
||||
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3)
|
||||
.setString(PACKAGE_1, "301:::true").build());
|
||||
mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
|
||||
doThrow(new RemoteException()).when(mPlatformCompat).putOverridesOnReleaseBuilds(
|
||||
argThat(config -> config.overrides.containsKey(201L)), eq(PACKAGE_1));
|
||||
|
||||
mPackageReceiver.onReceive(mMockContext,
|
||||
createPackageIntent(PACKAGE_1, ACTION_PACKAGE_ADDED));
|
||||
|
||||
verify(mPlatformCompat, times(3)).putOverridesOnReleaseBuilds(
|
||||
any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
|
||||
verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
|
||||
any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
|
||||
}
|
||||
|
||||
private void mockGetApplicationInfo(String packageName, long versionCode)
|
||||
throws Exception {
|
||||
when(mPackageManager.getApplicationInfo(eq(packageName), anyInt())).thenReturn(
|
||||
@@ -377,4 +681,8 @@ public class AppCompatOverridesServiceTest {
|
||||
appInfo.longVersionCode = versionCode;
|
||||
return appInfo;
|
||||
}
|
||||
|
||||
private Intent createPackageIntent(String packageName, @Nullable String action) {
|
||||
return new Intent(action, Uri.parse("package:" + packageName));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user