Merge "OMS: add internal tests" into qt-dev

This commit is contained in:
Todd Kennedy
2019-04-09 20:20:49 +00:00
committed by Android (Google) Code Review
5 changed files with 1022 additions and 3 deletions

View File

@@ -451,7 +451,7 @@ public final class OverlayInfo implements Parcelable {
public String toString() {
return "OverlayInfo { overlay=" + packageName + ", targetPackage=" + targetPackageName
+ ((targetOverlayableName == null) ? ""
: ", targetOverlyabale=" + targetOverlayableName)
: ", targetOverlayable=" + targetOverlayableName)
+ ", state=" + state + " (" + stateToString(state) + "), userId=" + userId + " }";
}
}

View File

@@ -166,6 +166,13 @@ import java.util.concurrent.atomic.AtomicBoolean;
* . . . . . . . . . . . . . . . . . . . . . .
* </pre>
*
* <p>To test the OMS, execute:
* <code>
* atest FrameworksServicesTests:com.android.server.om # internal tests
* atest OverlayDeviceTests OverlayHostTests # public API tests
* </code>
* </p>
*
* <p>Finally, here is a list of keywords used in the OMS context.</p>
*
* <ul>

View File

@@ -26,6 +26,7 @@ import android.util.ArrayMap;
import android.util.Slog;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
@@ -327,7 +328,8 @@ final class OverlayManagerSettings {
Serializer.persist(mItems, os);
}
private static final class Serializer {
@VisibleForTesting
static final class Serializer {
private static final String TAG_OVERLAYS = "overlays";
private static final String TAG_ITEM = "item";
@@ -343,7 +345,8 @@ final class OverlayManagerSettings {
private static final String ATTR_USER_ID = "userId";
private static final String ATTR_VERSION = "version";
private static final int CURRENT_VERSION = 3;
@VisibleForTesting
static final int CURRENT_VERSION = 3;
public static void restore(@NonNull final ArrayList<SettingsItem> table,
@NonNull final InputStream is) throws IOException, XmlPullParserException {

View File

@@ -0,0 +1,504 @@
/*
* 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.om;
import static android.content.om.OverlayInfo.STATE_DISABLED;
import static android.content.om.OverlayInfo.STATE_ENABLED;
import static android.content.om.OverlayInfo.STATE_MISSING_TARGET;
import static android.content.om.OverlayInfo.STATE_TARGET_IS_BEING_REPLACED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.annotation.NonNull;
import android.content.om.OverlayInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.util.ArraySet;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@RunWith(AndroidJUnit4.class)
public class OverlayManagerServiceImplTests {
private OverlayManagerServiceImpl mImpl;
private DummyDeviceState mState;
private DummyListener mListener;
private static final String OVERLAY = "com.dummy.overlay";
private static final String TARGET = "com.dummy.target";
private static final int USER = 0;
private static final String OVERLAY2 = OVERLAY + "2";
private static final String TARGET2 = TARGET + "2";
private static final int USER2 = USER + 1;
private static final String OVERLAY3 = OVERLAY + "3";
private static final int USER3 = USER2 + 1;
@Before
public void setUp() throws Exception {
mState = new DummyDeviceState();
mListener = new DummyListener();
DummyPackageManagerHelper pmh = new DummyPackageManagerHelper(mState);
mImpl = new OverlayManagerServiceImpl(pmh,
new DummyIdmapManager(mState, pmh),
new OverlayManagerSettings(),
new String[0],
mListener);
}
// tests: basics
@Test
public void testGetOverlayInfo() throws Exception {
installOverlayPackage(OVERLAY, TARGET, USER, false);
final OverlayInfo oi = mImpl.getOverlayInfo(OVERLAY, USER);
assertNotNull(oi);
assertEquals(oi.packageName, OVERLAY);
assertEquals(oi.targetPackageName, TARGET);
assertEquals(oi.userId, USER);
}
@Test
public void testGetOverlayInfosForTarget() throws Exception {
installOverlayPackage(OVERLAY, TARGET, USER, false);
installOverlayPackage(OVERLAY2, TARGET, USER, false);
installOverlayPackage(OVERLAY3, TARGET, USER2, false);
final List<OverlayInfo> ois = mImpl.getOverlayInfosForTarget(TARGET, USER);
assertEquals(ois.size(), 2);
assertTrue(ois.contains(mImpl.getOverlayInfo(OVERLAY, USER)));
assertTrue(ois.contains(mImpl.getOverlayInfo(OVERLAY2, USER)));
final List<OverlayInfo> ois2 = mImpl.getOverlayInfosForTarget(TARGET, USER2);
assertEquals(ois2.size(), 1);
assertTrue(ois2.contains(mImpl.getOverlayInfo(OVERLAY3, USER2)));
final List<OverlayInfo> ois3 = mImpl.getOverlayInfosForTarget(TARGET, USER3);
assertNotNull(ois3);
assertEquals(ois3.size(), 0);
final List<OverlayInfo> ois4 = mImpl.getOverlayInfosForTarget("no.such.overlay", USER);
assertNotNull(ois4);
assertEquals(ois4.size(), 0);
}
@Test
public void testGetOverlayInfosForUser() throws Exception {
installOverlayPackage(OVERLAY, TARGET, USER, false);
installOverlayPackage(OVERLAY2, TARGET, USER, false);
installOverlayPackage(OVERLAY3, TARGET2, USER, false);
final Map<String, List<OverlayInfo>> everything = mImpl.getOverlaysForUser(USER);
assertEquals(everything.size(), 2);
final List<OverlayInfo> ois = everything.get(TARGET);
assertNotNull(ois);
assertEquals(ois.size(), 2);
assertTrue(ois.contains(mImpl.getOverlayInfo(OVERLAY, USER)));
assertTrue(ois.contains(mImpl.getOverlayInfo(OVERLAY2, USER)));
final List<OverlayInfo> ois2 = everything.get(TARGET2);
assertNotNull(ois2);
assertEquals(ois2.size(), 1);
assertTrue(ois2.contains(mImpl.getOverlayInfo(OVERLAY3, USER)));
final Map<String, List<OverlayInfo>> everything2 = mImpl.getOverlaysForUser(USER2);
assertNotNull(everything2);
assertEquals(everything2.size(), 0);
}
@Test
public void testPriority() throws Exception {
installOverlayPackage(OVERLAY, TARGET, USER, false);
installOverlayPackage(OVERLAY2, TARGET, USER, false);
installOverlayPackage(OVERLAY3, TARGET, USER, false);
final OverlayInfo o1 = mImpl.getOverlayInfo(OVERLAY, USER);
final OverlayInfo o2 = mImpl.getOverlayInfo(OVERLAY2, USER);
final OverlayInfo o3 = mImpl.getOverlayInfo(OVERLAY3, USER);
assertOverlayInfoList(TARGET, USER, o1, o2, o3);
assertTrue(mImpl.setLowestPriority(OVERLAY3, USER));
assertOverlayInfoList(TARGET, USER, o3, o1, o2);
assertTrue(mImpl.setHighestPriority(OVERLAY3, USER));
assertOverlayInfoList(TARGET, USER, o1, o2, o3);
assertTrue(mImpl.setPriority(OVERLAY, OVERLAY2, USER));
assertOverlayInfoList(TARGET, USER, o2, o1, o3);
}
@Test
public void testOverlayInfoStateTransitions() throws Exception {
assertNull(mImpl.getOverlayInfo(OVERLAY, USER));
installOverlayPackage(OVERLAY, TARGET, USER, true);
assertState(STATE_MISSING_TARGET, OVERLAY, USER);
installTargetPackage(TARGET, USER);
assertState(STATE_DISABLED, OVERLAY, USER);
mImpl.setEnabled(OVERLAY, true, USER);
assertState(STATE_ENABLED, OVERLAY, USER);
beginUpgradeTargetPackage(TARGET, USER);
assertState(STATE_TARGET_IS_BEING_REPLACED, OVERLAY, USER);
endUpgradeTargetPackage(TARGET, USER);
assertState(STATE_ENABLED, OVERLAY, USER);
uninstallTargetPackage(TARGET, USER);
assertState(STATE_MISSING_TARGET, OVERLAY, USER);
installTargetPackage(TARGET, USER);
assertState(STATE_ENABLED, OVERLAY, USER);
}
@Test
public void testUpdateOverlaysForUser() throws Exception {
installTargetPackage(TARGET, USER);
installTargetPackage("some.other.target", USER);
installOverlayPackage(OVERLAY, TARGET, USER, true);
// do nothing, expect no change
List<String> a = mImpl.updateOverlaysForUser(USER);
assertEquals(1, a.size());
assertTrue(a.contains(TARGET));
// upgrade overlay, keep target
upgradeOverlayPackage(OVERLAY, TARGET, USER, true);
List<String> b = mImpl.updateOverlaysForUser(USER);
assertEquals(1, b.size());
assertTrue(b.contains(TARGET));
// do nothing, expect no change
List<String> c = mImpl.updateOverlaysForUser(USER);
assertEquals(1, c.size());
assertTrue(c.contains(TARGET));
// upgrade overlay, switch to new target
upgradeOverlayPackage(OVERLAY, "some.other.target", USER, true);
List<String> d = mImpl.updateOverlaysForUser(USER);
assertEquals(2, d.size());
assertTrue(d.containsAll(Arrays.asList(TARGET, "some.other.target")));
// do nothing, expect no change
List<String> e = mImpl.updateOverlaysForUser(USER);
assertEquals(1, e.size());
assertTrue(e.contains("some.other.target"));
}
@Test
public void testOnOverlayPackageUpgraded() throws Exception {
installTargetPackage(TARGET, USER);
installOverlayPackage(OVERLAY, TARGET, USER, true);
mImpl.onOverlayPackageReplacing(OVERLAY, USER);
mListener.count = 0;
mImpl.onOverlayPackageReplaced(OVERLAY, USER);
assertEquals(1, mListener.count);
// upgrade to a version where the overlay has changed its target
upgradeOverlayPackage(OVERLAY, "some.other.target", USER, true);
mImpl.onOverlayPackageReplacing(OVERLAY, USER);
mListener.count = 0;
mImpl.onOverlayPackageReplaced(OVERLAY, USER);
// expect once for the old target package, once for the new target package
assertEquals(2, mListener.count);
upgradeOverlayPackage(OVERLAY, "some.other.target", USER, true);
mImpl.onOverlayPackageReplacing(OVERLAY, USER);
mListener.count = 0;
mImpl.onOverlayPackageReplaced(OVERLAY, USER);
assertEquals(1, mListener.count);
}
// tests: listener interface
@Test
public void testListener() throws Exception {
installOverlayPackage(OVERLAY, TARGET, USER, true);
assertEquals(1, mListener.count);
mListener.count = 0;
installTargetPackage(TARGET, USER);
assertEquals(1, mListener.count);
mListener.count = 0;
mImpl.setEnabled(OVERLAY, true, USER);
assertEquals(1, mListener.count);
mListener.count = 0;
mImpl.setEnabled(OVERLAY, true, USER);
assertEquals(0, mListener.count);
}
// helper methods
private void assertState(int expected, final String overlayPackageName, int userId) {
int actual = mImpl.getOverlayInfo(OVERLAY, USER).state;
String msg = String.format("expected %s but was %s:",
OverlayInfo.stateToString(expected), OverlayInfo.stateToString(actual));
assertEquals(msg, expected, actual);
}
private void assertOverlayInfoList(final String targetPackageName, int userId,
OverlayInfo... overlayInfos) {
final List<OverlayInfo> expected =
mImpl.getOverlayInfosForTarget(targetPackageName, userId);
final List<OverlayInfo> actual = Arrays.asList(overlayInfos);
assertEquals(expected, actual);
}
private void installTargetPackage(String packageName, int userId) {
if (mState.select(packageName, userId) != null) {
throw new IllegalStateException("package already installed");
}
mState.add(packageName, null, userId, false);
mImpl.onTargetPackageAdded(packageName, userId);
}
private void beginUpgradeTargetPackage(String packageName, int userId) {
if (mState.select(packageName, userId) == null) {
throw new IllegalStateException("package not installed");
}
mState.add(packageName, null, userId, false);
mImpl.onTargetPackageReplacing(packageName, userId);
}
private void endUpgradeTargetPackage(String packageName, int userId) {
if (mState.select(packageName, userId) == null) {
throw new IllegalStateException("package not installed");
}
mState.add(packageName, null, userId, false);
mImpl.onTargetPackageReplaced(packageName, userId);
}
private void uninstallTargetPackage(String packageName, int userId) {
if (mState.select(packageName, userId) == null) {
throw new IllegalStateException("package not installed");
}
mState.remove(packageName, userId);
mImpl.onTargetPackageRemoved(packageName, userId);
}
private void installOverlayPackage(String packageName, String targetPackageName, int userId,
boolean canCreateIdmap) {
if (mState.select(packageName, userId) != null) {
throw new IllegalStateException("package already installed");
}
mState.add(packageName, targetPackageName, userId, canCreateIdmap);
mImpl.onOverlayPackageAdded(packageName, userId);
}
private void upgradeOverlayPackage(String packageName, String targetPackageName, int userId,
boolean canCreateIdmap) {
DummyDeviceState.Package pkg = mState.select(packageName, userId);
if (pkg == null) {
throw new IllegalStateException("package not installed, cannot upgrade");
}
pkg.targetPackageName = targetPackageName;
pkg.canCreateIdmap = canCreateIdmap;
}
private void uninstallOverlayPackage(String packageName, int userId) {
// implement this when adding support for downloadable overlays
throw new IllegalArgumentException("not implemented");
}
private static final class DummyDeviceState {
private List<Package> mPackages = new ArrayList<>();
public void add(String packageName, String targetPackageName, int userId,
boolean canCreateIdmap) {
remove(packageName, userId);
Package pkg = new Package();
pkg.packageName = packageName;
pkg.targetPackageName = targetPackageName;
pkg.userId = userId;
pkg.canCreateIdmap = canCreateIdmap;
mPackages.add(pkg);
}
public void remove(String packageName, int userId) {
final Iterator<Package> iter = mPackages.iterator();
while (iter.hasNext()) {
final Package pkg = iter.next();
if (pkg.packageName.equals(packageName) && pkg.userId == userId) {
iter.remove();
return;
}
}
}
public List<Package> select(int userId) {
List<Package> out = new ArrayList<>();
final int packageCount = mPackages.size();
for (int i = 0; i < packageCount; i++) {
final Package pkg = mPackages.get(i);
if (pkg.userId == userId) {
out.add(pkg);
}
}
return out;
}
public Package select(String packageName, int userId) {
final int packageCount = mPackages.size();
for (int i = 0; i < packageCount; i++) {
final Package pkg = mPackages.get(i);
if (pkg.packageName.equals(packageName) && pkg.userId == userId) {
return pkg;
}
}
return null;
}
private static final class Package {
public String packageName;
public int userId;
public String targetPackageName;
public boolean canCreateIdmap;
}
}
private static final class DummyPackageManagerHelper implements
OverlayManagerServiceImpl.PackageManagerHelper {
private final DummyDeviceState mState;
DummyPackageManagerHelper(DummyDeviceState state) {
mState = state;
}
@Override
public PackageInfo getPackageInfo(@NonNull String packageName, int userId) {
final DummyDeviceState.Package pkg = mState.select(packageName, userId);
if (pkg == null) {
return null;
}
ApplicationInfo ai = new ApplicationInfo();
ai.sourceDir = String.format("%s/%s/base.apk",
pkg.targetPackageName == null ? "/system/app/" : "/vendor/overlay/",
pkg.packageName);
PackageInfo pi = new PackageInfo();
pi.applicationInfo = ai;
pi.packageName = pkg.packageName;
pi.overlayTarget = pkg.targetPackageName;
pi.overlayCategory = "dummy-category-" + pkg.targetPackageName;
return pi;
}
@Override
public boolean signaturesMatching(@NonNull String packageName1,
@NonNull String packageName2, int userId) {
return false;
}
@Override
public List<PackageInfo> getOverlayPackages(int userId) {
List<PackageInfo> out = new ArrayList<>();
final List<DummyDeviceState.Package> packages = mState.select(userId);
final int packageCount = packages.size();
for (int i = 0; i < packageCount; i++) {
final DummyDeviceState.Package pkg = packages.get(i);
if (pkg.targetPackageName != null) {
out.add(getPackageInfo(pkg.packageName, pkg.userId));
}
}
return out;
}
}
private static class DummyIdmapManager extends IdmapManager {
private final DummyDeviceState mState;
private Set<String> mIdmapFiles = new ArraySet<>();
DummyIdmapManager(DummyDeviceState state, DummyPackageManagerHelper packageManagerHelper) {
super(null, packageManagerHelper);
mState = state;
}
@Override
boolean createIdmap(@NonNull final PackageInfo targetPackage,
@NonNull final PackageInfo overlayPackage, int userId) {
final DummyDeviceState.Package t = mState.select(targetPackage.packageName, userId);
if (t == null) {
return false;
}
final DummyDeviceState.Package o = mState.select(overlayPackage.packageName, userId);
if (o == null) {
return false;
}
if (!o.canCreateIdmap) {
return false;
}
final String key = createKey(overlayPackage.packageName, userId);
mIdmapFiles.add(key);
return true;
}
@Override
boolean removeIdmap(@NonNull final OverlayInfo oi, final int userId) {
final String key = createKey(oi.packageName, oi.userId);
if (!mIdmapFiles.contains(key)) {
return false;
}
mIdmapFiles.remove(key);
return true;
}
@Override
boolean idmapExists(@NonNull final OverlayInfo oi) {
final String key = createKey(oi.packageName, oi.userId);
return mIdmapFiles.contains(key);
}
@Override
boolean idmapExists(@NonNull final PackageInfo overlayPackage, final int userId) {
final String key = createKey(overlayPackage.packageName, userId);
return mIdmapFiles.contains(key);
}
private String createKey(@NonNull final String packageName, final int userId) {
return String.format("%s:%d", packageName, userId);
}
}
private static class DummyListener implements OverlayManagerServiceImpl.OverlayChangeListener {
public int count;
public void onOverlaysChanged(@NonNull String targetPackage, int userId) {
count++;
}
}
}

View File

@@ -0,0 +1,505 @@
/*
* 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.om;
import static android.content.om.OverlayInfo.STATE_DISABLED;
import static android.content.om.OverlayInfo.STATE_ENABLED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.content.om.OverlayInfo;
import android.text.TextUtils;
import android.util.Xml;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.xmlpull.v1.XmlPullParser;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;
import java.util.stream.Stream;
@RunWith(AndroidJUnit4.class)
public class OverlayManagerSettingsTests {
private OverlayManagerSettings mSettings;
private static final OverlayInfo OVERLAY_A0 = new OverlayInfo(
"com.dummy.overlay_a",
"com.dummy.target",
null,
"some-category",
"/data/app/com.dummy.overlay_a-1/base.apk",
STATE_DISABLED,
0,
0,
false);
private static final OverlayInfo OVERLAY_B0 = new OverlayInfo(
"com.dummy.overlay_b",
"com.dummy.target",
null,
"some-category",
"/data/app/com.dummy.overlay_b-1/base.apk",
STATE_DISABLED,
0,
0,
false);
private static final OverlayInfo OVERLAY_C0 = new OverlayInfo(
"com.dummy.overlay_c",
"com.dummy.target",
null,
"some-category",
"/data/app/com.dummy.overlay_c-1/base.apk",
STATE_DISABLED,
0,
0,
false);
private static final OverlayInfo OVERLAY_A1 = new OverlayInfo(
"com.dummy.overlay_a",
"com.dummy.target",
null,
"some-category",
"/data/app/com.dummy.overlay_a-1/base.apk",
STATE_DISABLED,
1,
0,
false);
private static final OverlayInfo OVERLAY_B1 = new OverlayInfo(
"com.dummy.overlay_b",
"com.dummy.target",
null,
"some-category",
"/data/app/com.dummy.overlay_b-1/base.apk",
STATE_DISABLED,
1,
0,
false);
@Before
public void setUp() throws Exception {
mSettings = new OverlayManagerSettings();
}
// tests: generic functionality
@Test
public void testSettingsInitiallyEmpty() throws Exception {
final int userId = 0;
Map<String, List<OverlayInfo>> map = mSettings.getOverlaysForUser(userId);
assertEquals(0, map.size());
}
@Test
public void testBasicSetAndGet() throws Exception {
assertDoesNotContain(mSettings, OVERLAY_A0.packageName, OVERLAY_A0.userId);
insert(OVERLAY_A0);
assertContains(mSettings, OVERLAY_A0);
OverlayInfo oi = mSettings.getOverlayInfo(OVERLAY_A0.packageName, OVERLAY_A0.userId);
assertEquals(OVERLAY_A0, oi);
assertTrue(mSettings.remove(OVERLAY_A0.packageName, OVERLAY_A0.userId));
assertDoesNotContain(mSettings, OVERLAY_A0.packageName, OVERLAY_A0.userId);
}
@Test
public void testGetUsers() throws Exception {
int[] users = mSettings.getUsers();
assertEquals(0, users.length);
insert(OVERLAY_A0);
users = mSettings.getUsers();
assertEquals(1, users.length);
assertContains(users, OVERLAY_A0.userId);
insert(OVERLAY_A1);
insert(OVERLAY_B1);
users = mSettings.getUsers();
assertEquals(2, users.length);
assertContains(users, OVERLAY_A0.userId);
assertContains(users, OVERLAY_A1.userId);
}
@Test
public void testGetOverlaysForUser() throws Exception {
insert(OVERLAY_A0);
insert(OVERLAY_B0);
insert(OVERLAY_A1);
insert(OVERLAY_B1);
Map<String, List<OverlayInfo>> map = mSettings.getOverlaysForUser(OVERLAY_A0.userId);
assertEquals(1, map.keySet().size());
assertTrue(map.keySet().contains(OVERLAY_A0.targetPackageName));
List<OverlayInfo> list = map.get(OVERLAY_A0.targetPackageName);
assertEquals(2, list.size());
assertTrue(list.contains(OVERLAY_A0));
assertTrue(list.contains(OVERLAY_B0));
// getOverlaysForUser should never return null
map = mSettings.getOverlaysForUser(-1);
assertNotNull(map);
assertEquals(0, map.size());
}
@Test
public void testRemoveUser() throws Exception {
insert(OVERLAY_A0);
insert(OVERLAY_B0);
insert(OVERLAY_A1);
assertContains(mSettings, OVERLAY_A0);
assertContains(mSettings, OVERLAY_B0);
assertContains(mSettings, OVERLAY_A1);
mSettings.removeUser(OVERLAY_A0.userId);
assertDoesNotContain(mSettings, OVERLAY_A0);
assertDoesNotContain(mSettings, OVERLAY_B0);
assertContains(mSettings, OVERLAY_A1);
}
@Test
public void testOrderOfNewlyAddedItems() throws Exception {
// new items are appended to the list
insert(OVERLAY_A0);
insert(OVERLAY_B0);
insert(OVERLAY_C0);
List<OverlayInfo> list =
mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
assertListsAreEqual(list, OVERLAY_A0, OVERLAY_B0, OVERLAY_C0);
// overlays keep their positions when updated
mSettings.setState(OVERLAY_B0.packageName, OVERLAY_B0.userId, STATE_ENABLED);
OverlayInfo oi = mSettings.getOverlayInfo(OVERLAY_B0.packageName, OVERLAY_B0.userId);
list = mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
assertListsAreEqual(list, OVERLAY_A0, oi, OVERLAY_C0);
}
@Test
public void testSetPriority() throws Exception {
insert(OVERLAY_A0);
insert(OVERLAY_B0);
insert(OVERLAY_C0);
List<OverlayInfo> list =
mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
assertListsAreEqual(list, OVERLAY_A0, OVERLAY_B0, OVERLAY_C0);
boolean changed = mSettings.setPriority(OVERLAY_B0.packageName, OVERLAY_C0.packageName,
OVERLAY_B0.userId);
assertTrue(changed);
list = mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
assertListsAreEqual(list, OVERLAY_A0, OVERLAY_C0, OVERLAY_B0);
changed =
mSettings.setPriority(OVERLAY_B0.packageName, "does.not.exist", OVERLAY_B0.userId);
assertFalse(changed);
list = mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
assertListsAreEqual(list, OVERLAY_A0, OVERLAY_C0, OVERLAY_B0);
OverlayInfo otherTarget = new OverlayInfo(
"com.dummy.overlay_other",
"com.dummy.some.other.target",
null,
"some-category",
"/data/app/com.dummy.overlay_other-1/base.apk",
STATE_DISABLED,
0,
0,
false);
insert(otherTarget);
changed = mSettings.setPriority(OVERLAY_A0.packageName, otherTarget.packageName,
OVERLAY_A0.userId);
assertFalse(changed);
}
@Test
public void testSetLowestPriority() throws Exception {
insert(OVERLAY_A0);
insert(OVERLAY_B0);
insert(OVERLAY_C0);
List<OverlayInfo> list =
mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
assertListsAreEqual(list, OVERLAY_A0, OVERLAY_B0, OVERLAY_C0);
boolean changed = mSettings.setLowestPriority(OVERLAY_B0.packageName, OVERLAY_B0.userId);
assertTrue(changed);
list = mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
assertListsAreEqual(list, OVERLAY_B0, OVERLAY_A0, OVERLAY_C0);
}
@Test
public void testSetHighestPriority() throws Exception {
insert(OVERLAY_A0);
insert(OVERLAY_B0);
insert(OVERLAY_C0);
List<OverlayInfo> list =
mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
assertListsAreEqual(list, OVERLAY_A0, OVERLAY_B0, OVERLAY_C0);
boolean changed = mSettings.setHighestPriority(OVERLAY_B0.packageName, OVERLAY_B0.userId);
assertTrue(changed);
list = mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
assertListsAreEqual(list, OVERLAY_A0, OVERLAY_C0, OVERLAY_B0);
}
// tests: persist and restore
@Test
public void testPersistEmpty() throws Exception {
ByteArrayOutputStream os = new ByteArrayOutputStream();
mSettings.persist(os);
String xml = new String(os.toByteArray(), "utf-8");
assertEquals(1, countXmlTags(xml, "overlays"));
assertEquals(0, countXmlTags(xml, "item"));
}
@Test
public void testPersistDifferentOverlaysSameUser() throws Exception {
insert(OVERLAY_A0);
insert(OVERLAY_B0);
ByteArrayOutputStream os = new ByteArrayOutputStream();
mSettings.persist(os);
final String xml = new String(os.toByteArray(), "utf-8");
assertEquals(1, countXmlTags(xml, "overlays"));
assertEquals(2, countXmlTags(xml, "item"));
assertEquals(1, countXmlAttributesWhere(xml, "item", "packageName",
OVERLAY_A0.packageName));
assertEquals(1, countXmlAttributesWhere(xml, "item", "packageName",
OVERLAY_B0.packageName));
assertEquals(2, countXmlAttributesWhere(xml, "item", "userId",
Integer.toString(OVERLAY_A0.userId)));
}
@Test
public void testPersistSameOverlayDifferentUsers() throws Exception {
insert(OVERLAY_A0);
insert(OVERLAY_A1);
ByteArrayOutputStream os = new ByteArrayOutputStream();
mSettings.persist(os);
String xml = new String(os.toByteArray(), "utf-8");
assertEquals(1, countXmlTags(xml, "overlays"));
assertEquals(2, countXmlTags(xml, "item"));
assertEquals(2, countXmlAttributesWhere(xml, "item", "packageName",
OVERLAY_A0.packageName));
assertEquals(1, countXmlAttributesWhere(xml, "item", "userId",
Integer.toString(OVERLAY_A0.userId)));
assertEquals(1, countXmlAttributesWhere(xml, "item", "userId",
Integer.toString(OVERLAY_A1.userId)));
}
@Test
public void testPersistEnabled() throws Exception {
insert(OVERLAY_A0);
mSettings.setEnabled(OVERLAY_A0.packageName, OVERLAY_A0.userId, true);
ByteArrayOutputStream os = new ByteArrayOutputStream();
mSettings.persist(os);
String xml = new String(os.toByteArray(), "utf-8");
assertEquals(1, countXmlAttributesWhere(xml, "item", "isEnabled", "true"));
}
@Test
public void testRestoreEmpty() throws Exception {
final int version = OverlayManagerSettings.Serializer.CURRENT_VERSION;
final String xml =
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ "<overlays version=\"" + version + "\" />\n";
ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes("utf-8"));
mSettings.restore(is);
assertDoesNotContain(mSettings, "com.dummy.overlay", 0);
}
@Test
public void testRestoreSingleUserSingleOverlay() throws Exception {
final int version = OverlayManagerSettings.Serializer.CURRENT_VERSION;
final String xml =
"<?xml version='1.0' encoding='utf-8' standalone='yes'?>\n"
+ "<overlays version='" + version + "'>\n"
+ "<item packageName='com.dummy.overlay'\n"
+ " userId='1234'\n"
+ " targetPackageName='com.dummy.target'\n"
+ " baseCodePath='/data/app/com.dummy.overlay-1/base.apk'\n"
+ " state='" + STATE_DISABLED + "'\n"
+ " isEnabled='false'\n"
+ " category='dummy-category'\n"
+ " isStatic='false'\n"
+ " priority='0' />\n"
+ "</overlays>\n";
ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes("utf-8"));
mSettings.restore(is);
OverlayInfo oi = mSettings.getOverlayInfo("com.dummy.overlay", 1234);
assertNotNull(oi);
assertEquals("com.dummy.overlay", oi.packageName);
assertEquals("com.dummy.target", oi.targetPackageName);
assertEquals("/data/app/com.dummy.overlay-1/base.apk", oi.baseCodePath);
assertEquals(1234, oi.userId);
assertEquals(STATE_DISABLED, oi.state);
assertFalse(mSettings.getEnabled("com.dummy.overlay", 1234));
}
@Test
public void testPersistAndRestore() throws Exception {
insert(OVERLAY_A0);
insert(OVERLAY_B1);
ByteArrayOutputStream os = new ByteArrayOutputStream();
mSettings.persist(os);
String xml = new String(os.toByteArray(), "utf-8");
ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes("utf-8"));
OverlayManagerSettings newSettings = new OverlayManagerSettings();
newSettings.restore(is);
OverlayInfo a = newSettings.getOverlayInfo(OVERLAY_A0.packageName, OVERLAY_A0.userId);
assertEquals(OVERLAY_A0, a);
OverlayInfo b = newSettings.getOverlayInfo(OVERLAY_B1.packageName, OVERLAY_B1.userId);
assertEquals(OVERLAY_B1, b);
}
private int countXmlTags(String xml, String tagToLookFor) throws Exception {
int count = 0;
XmlPullParser parser = Xml.newPullParser();
parser.setInput(new StringReader(xml));
int event = parser.getEventType();
while (event != XmlPullParser.END_DOCUMENT) {
if (event == XmlPullParser.START_TAG && tagToLookFor.equals(parser.getName())) {
count++;
}
event = parser.next();
}
return count;
}
private int countXmlAttributesWhere(String xml, String tag, String attr, String value)
throws Exception {
int count = 0;
XmlPullParser parser = Xml.newPullParser();
parser.setInput(new StringReader(xml));
int event = parser.getEventType();
while (event != XmlPullParser.END_DOCUMENT) {
if (event == XmlPullParser.START_TAG && tag.equals(parser.getName())) {
String v = parser.getAttributeValue(null, attr);
if (value.equals(v)) {
count++;
}
}
event = parser.next();
}
return count;
}
private void insert(OverlayInfo oi) throws Exception {
mSettings.init(oi.packageName, oi.userId, oi.targetPackageName, null, oi.baseCodePath,
false, 0, oi.category);
mSettings.setState(oi.packageName, oi.userId, oi.state);
mSettings.setEnabled(oi.packageName, oi.userId, false);
}
private static void assertContains(final OverlayManagerSettings settings,
final OverlayInfo oi) {
assertContains(settings, oi.packageName, oi.userId);
}
private static void assertContains(final OverlayManagerSettings settings,
final String packageName, int userId) {
try {
settings.getOverlayInfo(packageName, userId);
} catch (OverlayManagerSettings.BadKeyException e) {
fail(String.format("settings does not contain packageName=%s userId=%d",
packageName, userId));
}
}
private static void assertDoesNotContain(final OverlayManagerSettings settings,
final OverlayInfo oi) {
assertDoesNotContain(settings, oi.packageName, oi.userId);
}
private static void assertDoesNotContain(final OverlayManagerSettings settings,
final String packageName, int userId) {
try {
settings.getOverlayInfo(packageName, userId);
fail(String.format("settings contains packageName=%s userId=%d", packageName, userId));
} catch (OverlayManagerSettings.BadKeyException e) {
// do nothing: we expect to end up here
}
}
private static void assertContains(int[] haystack, int needle) {
List<Integer> list = IntStream.of(haystack)
.boxed()
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
if (!list.contains(needle)) {
fail(String.format("integer array [%s] does not contain value %s",
TextUtils.join(",", list), needle));
}
}
private static void assertDoesNotContain(int[] haystack, int needle) {
List<Integer> list = IntStream.of(haystack)
.boxed()
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
if (list.contains(needle)) {
fail(String.format("integer array [%s] contains value %s",
TextUtils.join(",", list), needle));
}
}
private static void assertListsAreEqual(List<OverlayInfo> list, OverlayInfo... array) {
List<OverlayInfo> other = Stream.of(array)
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
assertListsAreEqual(list, other);
}
private static void assertListsAreEqual(List<OverlayInfo> list, List<OverlayInfo> other) {
if (!list.equals(other)) {
fail(String.format("lists [%s] and [%s] differ",
TextUtils.join(",", list), TextUtils.join(",", other)));
}
}
}