Merge "Add Listeners to PlatformCompat"
am: e14d7099a9
Change-Id: Id187394dc3f52f560faac6b9c73dea40119a5eff
This commit is contained in:
@@ -38,6 +38,20 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public final class CompatChange extends CompatibilityChangeInfo {
|
public final class CompatChange extends CompatibilityChangeInfo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback listener for when compat changes are updated for a package.
|
||||||
|
* See {@link #registerListener(ChangeListener)} for more details.
|
||||||
|
*/
|
||||||
|
public interface ChangeListener {
|
||||||
|
/**
|
||||||
|
* Called upon an override change for packageName and the change this listener is
|
||||||
|
* registered for. Called before the app is killed.
|
||||||
|
*/
|
||||||
|
void onCompatChange(String packageName);
|
||||||
|
}
|
||||||
|
|
||||||
|
ChangeListener mListener = null;
|
||||||
|
|
||||||
private Map<String, Boolean> mPackageOverrides;
|
private Map<String, Boolean> mPackageOverrides;
|
||||||
|
|
||||||
public CompatChange(long changeId) {
|
public CompatChange(long changeId) {
|
||||||
@@ -64,6 +78,15 @@ public final class CompatChange extends CompatibilityChangeInfo {
|
|||||||
change.getDisabled());
|
change.getDisabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void registerListener(ChangeListener listener) {
|
||||||
|
if (mListener != null) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Listener for change " + toString() + " already registered.");
|
||||||
|
}
|
||||||
|
mListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Force the enabled state of this change for a given package name. The change will only take
|
* Force the enabled state of this change for a given package name. The change will only take
|
||||||
* effect after that packages process is killed and restarted.
|
* effect after that packages process is killed and restarted.
|
||||||
@@ -78,6 +101,7 @@ public final class CompatChange extends CompatibilityChangeInfo {
|
|||||||
mPackageOverrides = new HashMap<>();
|
mPackageOverrides = new HashMap<>();
|
||||||
}
|
}
|
||||||
mPackageOverrides.put(pname, enabled);
|
mPackageOverrides.put(pname, enabled);
|
||||||
|
notifyListener(pname);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -89,7 +113,9 @@ public final class CompatChange extends CompatibilityChangeInfo {
|
|||||||
*/
|
*/
|
||||||
void removePackageOverride(String pname) {
|
void removePackageOverride(String pname) {
|
||||||
if (mPackageOverrides != null) {
|
if (mPackageOverrides != null) {
|
||||||
mPackageOverrides.remove(pname);
|
if (mPackageOverrides.remove(pname) != null) {
|
||||||
|
notifyListener(pname);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,4 +157,10 @@ public final class CompatChange extends CompatibilityChangeInfo {
|
|||||||
}
|
}
|
||||||
return sb.append(")").toString();
|
return sb.append(")").toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void notifyListener(String packageName) {
|
||||||
|
if (mListener != null) {
|
||||||
|
mListener.onCompatChange(packageName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ final class CompatConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all overrides previously added via {@link #addOverride(long, String, boolean)} or
|
* Removes all overrides previously added via {@link #addOverride(long, String, boolean)} or
|
||||||
* {@link #addAppOverrides(CompatibilityChangeConfig, String)} for a certain package.
|
* {@link #addOverrides(CompatibilityChangeConfig, String)} for a certain package.
|
||||||
*
|
*
|
||||||
* <p>This restores the default behaviour for the given change and app, once any app
|
* <p>This restores the default behaviour for the given change and app, once any app
|
||||||
* processes have been restarted.
|
* processes have been restarted.
|
||||||
@@ -243,6 +243,27 @@ final class CompatConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean registerListener(long changeId, CompatChange.ChangeListener listener) {
|
||||||
|
boolean alreadyKnown = true;
|
||||||
|
synchronized (mChanges) {
|
||||||
|
CompatChange c = mChanges.get(changeId);
|
||||||
|
if (c == null) {
|
||||||
|
alreadyKnown = false;
|
||||||
|
c = new CompatChange(changeId);
|
||||||
|
addChange(c);
|
||||||
|
}
|
||||||
|
c.registerListener(listener);
|
||||||
|
}
|
||||||
|
return alreadyKnown;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void clearChanges() {
|
||||||
|
synchronized (mChanges) {
|
||||||
|
mChanges.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dumps the current list of compatibility config information.
|
* Dumps the current list of compatibility config information.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -107,6 +107,23 @@ public class PlatformCompat extends IPlatformCompat.Stub {
|
|||||||
return enabled;
|
return enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a listener for change state overrides. Only one listener per change is allowed.
|
||||||
|
*
|
||||||
|
* <p>{@code listener.onCompatChange(String)} method is guaranteed to be called with
|
||||||
|
* packageName before the app is killed upon an override change. The state of a change is not
|
||||||
|
* guaranteed to change when {@code listener.onCompatChange(String)} is called.
|
||||||
|
*
|
||||||
|
* @param changeId to get updates for
|
||||||
|
* @param listener the listener that will be called upon a potential change for package.
|
||||||
|
* @throws IllegalStateException if a listener was already registered for changeId
|
||||||
|
* @returns {@code true} if a change with changeId was already known, or (@code false}
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
public boolean registerListener(long changeId, CompatChange.ChangeListener listener) {
|
||||||
|
return CompatConfig.get().registerListener(changeId, listener);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setOverrides(CompatibilityChangeConfig overrides, String packageName) {
|
public void setOverrides(CompatibilityChangeConfig overrides, String packageName) {
|
||||||
CompatConfig.get().addOverrides(overrides, packageName);
|
CompatConfig.get().addOverrides(overrides, packageName);
|
||||||
|
|||||||
@@ -0,0 +1,272 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.server.compat;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.reset;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import static org.mockito.internal.verification.VerificationModeFactory.times;
|
||||||
|
import static org.testng.Assert.assertThrows;
|
||||||
|
|
||||||
|
import android.compat.Compatibility;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
|
||||||
|
import com.android.internal.compat.CompatibilityChangeConfig;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class PlatformCompatTest {
|
||||||
|
private static final String PACKAGE_NAME = "my.package";
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Context mContext;
|
||||||
|
@Mock
|
||||||
|
private PackageManager mPackageManager;
|
||||||
|
@Mock
|
||||||
|
CompatChange.ChangeListener mListener1, mListener2;
|
||||||
|
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
when(mContext.getPackageManager()).thenReturn(mPackageManager);
|
||||||
|
when(mPackageManager.getPackageUid(eq(PACKAGE_NAME), eq(0))).thenThrow(
|
||||||
|
new PackageManager.NameNotFoundException());
|
||||||
|
CompatConfig.get().clearChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRegisterListenerToSameIdThrows() {
|
||||||
|
PlatformCompat pc = new PlatformCompat(mContext);
|
||||||
|
|
||||||
|
// Registering a listener to change 1 is successful.
|
||||||
|
pc.registerListener(1, mListener1);
|
||||||
|
// Registering a listener to change 2 is successful.
|
||||||
|
pc.registerListener(2, mListener1);
|
||||||
|
// Trying to register another listener to change id 1 fails.
|
||||||
|
assertThrows(IllegalStateException.class, () -> pc.registerListener(1, mListener1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRegisterListenerReturn() {
|
||||||
|
PlatformCompat pc = new PlatformCompat(mContext);
|
||||||
|
|
||||||
|
pc.setOverrides(
|
||||||
|
new CompatibilityChangeConfig(
|
||||||
|
new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
|
||||||
|
PACKAGE_NAME);
|
||||||
|
|
||||||
|
// Change id 1 is known (added in setOverrides).
|
||||||
|
assertThat(pc.registerListener(1, mListener1)).isTrue();
|
||||||
|
// Change 2 is unknown.
|
||||||
|
assertThat(pc.registerListener(2, mListener1)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListenerCalledOnSetOverrides() {
|
||||||
|
PlatformCompat pc = new PlatformCompat(mContext);
|
||||||
|
|
||||||
|
pc.registerListener(1, mListener1);
|
||||||
|
pc.registerListener(2, mListener1);
|
||||||
|
|
||||||
|
pc.setOverrides(
|
||||||
|
new CompatibilityChangeConfig(
|
||||||
|
new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
|
||||||
|
PACKAGE_NAME);
|
||||||
|
|
||||||
|
verify(mListener1, times(2)).onCompatChange(PACKAGE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListenerNotCalledOnWrongPackage() {
|
||||||
|
PlatformCompat pc = new PlatformCompat(mContext);
|
||||||
|
|
||||||
|
pc.registerListener(1, mListener1);
|
||||||
|
pc.registerListener(2, mListener1);
|
||||||
|
|
||||||
|
pc.setOverridesForTest(
|
||||||
|
new CompatibilityChangeConfig(
|
||||||
|
new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
|
||||||
|
PACKAGE_NAME);
|
||||||
|
|
||||||
|
verify(mListener1, never()).onCompatChange("other.package");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListenerCalledOnSetOverridesTwoListeners() {
|
||||||
|
PlatformCompat pc = new PlatformCompat(mContext);
|
||||||
|
pc.registerListener(1, mListener1);
|
||||||
|
|
||||||
|
final ImmutableSet<Long> enabled = ImmutableSet.of(1L);
|
||||||
|
final ImmutableSet<Long> disabled = ImmutableSet.of(2L);
|
||||||
|
|
||||||
|
pc.setOverrides(
|
||||||
|
new CompatibilityChangeConfig(
|
||||||
|
new Compatibility.ChangeConfig(enabled, disabled)),
|
||||||
|
PACKAGE_NAME);
|
||||||
|
|
||||||
|
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
|
||||||
|
verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
|
||||||
|
|
||||||
|
reset(mListener1);
|
||||||
|
reset(mListener2);
|
||||||
|
|
||||||
|
pc.registerListener(2, mListener2);
|
||||||
|
|
||||||
|
pc.setOverrides(
|
||||||
|
new CompatibilityChangeConfig(
|
||||||
|
new Compatibility.ChangeConfig(enabled, disabled)),
|
||||||
|
PACKAGE_NAME);
|
||||||
|
|
||||||
|
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
|
||||||
|
verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListenerCalledOnSetOverridesForTest() {
|
||||||
|
PlatformCompat pc = new PlatformCompat(mContext);
|
||||||
|
|
||||||
|
pc.registerListener(1, mListener1);
|
||||||
|
pc.registerListener(2, mListener1);
|
||||||
|
|
||||||
|
pc.setOverridesForTest(
|
||||||
|
new CompatibilityChangeConfig(
|
||||||
|
new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
|
||||||
|
PACKAGE_NAME);
|
||||||
|
|
||||||
|
verify(mListener1, times(2)).onCompatChange(PACKAGE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListenerCalledOnSetOverridesTwoListenersForTest() {
|
||||||
|
PlatformCompat pc = new PlatformCompat(mContext);
|
||||||
|
pc.registerListener(1, mListener1);
|
||||||
|
|
||||||
|
final ImmutableSet<Long> enabled = ImmutableSet.of(1L);
|
||||||
|
final ImmutableSet<Long> disabled = ImmutableSet.of(2L);
|
||||||
|
|
||||||
|
pc.setOverridesForTest(
|
||||||
|
new CompatibilityChangeConfig(
|
||||||
|
new Compatibility.ChangeConfig(enabled, disabled)),
|
||||||
|
PACKAGE_NAME);
|
||||||
|
|
||||||
|
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
|
||||||
|
verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
|
||||||
|
|
||||||
|
reset(mListener1);
|
||||||
|
reset(mListener2);
|
||||||
|
|
||||||
|
pc.registerListener(2, mListener2);
|
||||||
|
pc.setOverridesForTest(
|
||||||
|
new CompatibilityChangeConfig(
|
||||||
|
new Compatibility.ChangeConfig(enabled, disabled)),
|
||||||
|
PACKAGE_NAME);
|
||||||
|
|
||||||
|
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
|
||||||
|
verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListenerCalledOnClearOverrides() {
|
||||||
|
PlatformCompat pc = new PlatformCompat(mContext);
|
||||||
|
|
||||||
|
pc.registerListener(1, mListener1);
|
||||||
|
pc.registerListener(2, mListener2);
|
||||||
|
|
||||||
|
pc.setOverrides(
|
||||||
|
new CompatibilityChangeConfig(
|
||||||
|
new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
|
||||||
|
PACKAGE_NAME);
|
||||||
|
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
|
||||||
|
verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
|
||||||
|
|
||||||
|
reset(mListener1);
|
||||||
|
reset(mListener2);
|
||||||
|
|
||||||
|
pc.clearOverrides(PACKAGE_NAME);
|
||||||
|
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
|
||||||
|
verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListenerCalledOnClearOverridesMultipleOverrides() {
|
||||||
|
PlatformCompat pc = new PlatformCompat(mContext);
|
||||||
|
|
||||||
|
pc.registerListener(1, mListener1);
|
||||||
|
pc.registerListener(2, mListener2);
|
||||||
|
|
||||||
|
pc.setOverrides(
|
||||||
|
new CompatibilityChangeConfig(
|
||||||
|
new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
|
||||||
|
PACKAGE_NAME);
|
||||||
|
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
|
||||||
|
verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);
|
||||||
|
|
||||||
|
reset(mListener1);
|
||||||
|
reset(mListener2);
|
||||||
|
|
||||||
|
pc.clearOverrides(PACKAGE_NAME);
|
||||||
|
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
|
||||||
|
verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListenerCalledOnClearOverrideExists() {
|
||||||
|
PlatformCompat pc = new PlatformCompat(mContext);
|
||||||
|
|
||||||
|
pc.registerListener(1, mListener1);
|
||||||
|
pc.registerListener(2, mListener2);
|
||||||
|
|
||||||
|
pc.setOverrides(
|
||||||
|
new CompatibilityChangeConfig(
|
||||||
|
new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
|
||||||
|
PACKAGE_NAME);
|
||||||
|
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
|
||||||
|
verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
|
||||||
|
|
||||||
|
reset(mListener1);
|
||||||
|
reset(mListener2);
|
||||||
|
|
||||||
|
pc.clearOverride(1, PACKAGE_NAME);
|
||||||
|
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
|
||||||
|
verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListenerCalledOnClearOverrideDoesntExist() {
|
||||||
|
PlatformCompat pc = new PlatformCompat(mContext);
|
||||||
|
|
||||||
|
pc.registerListener(1, mListener1);
|
||||||
|
|
||||||
|
pc.clearOverride(1, PACKAGE_NAME);
|
||||||
|
// Listener not called when a non existing override is removed.
|
||||||
|
verify(mListener1, never()).onCompatChange(PACKAGE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user