cmsdk: Add preliminary ThemeManager test coverage.
TICKET: CYNGNOS-2307 Change-Id: Ie94ae3cd55678ecb2c631dc10d2335fb5d7362a7
This commit is contained in:
parent
d2e7e04bc4
commit
22859efbfd
|
@ -67,7 +67,8 @@ public class ThemeManager {
|
||||||
return sInstance;
|
return sInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IThemeService getService() {
|
/** @hide */
|
||||||
|
public static IThemeService getService() {
|
||||||
if (sService != null) {
|
if (sService != null) {
|
||||||
return sService;
|
return sService;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,11 @@
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.REBOOT" />
|
<uses-permission android:name="android.permission.REBOOT" />
|
||||||
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
|
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
|
||||||
|
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
|
||||||
|
|
||||||
<uses-permission android:name="cyanogenmod.permission.PUBLISH_CUSTOM_TILE" />
|
<uses-permission android:name="cyanogenmod.permission.PUBLISH_CUSTOM_TILE" />
|
||||||
<uses-permission android:name="cyanogenmod.permission.WRITE_SETTINGS"/>
|
<uses-permission android:name="cyanogenmod.permission.WRITE_SETTINGS"/>
|
||||||
<uses-permission android:name="cyanogenmod.permission.WRITE_SECURE_SETTINGS"/>
|
<uses-permission android:name="cyanogenmod.permission.WRITE_SECURE_SETTINGS"/>
|
||||||
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
|
|
||||||
<uses-permission android:name="cyanogenmod.permission.MODIFY_NETWORK_SETTINGS" />
|
<uses-permission android:name="cyanogenmod.permission.MODIFY_NETWORK_SETTINGS" />
|
||||||
<uses-permission android:name="cyanogenmod.permission.MODIFY_SOUND_SETTINGS" />
|
<uses-permission android:name="cyanogenmod.permission.MODIFY_SOUND_SETTINGS" />
|
||||||
<uses-permission android:name="cyanogenmod.permission.MANAGE_ALARMS" />
|
<uses-permission android:name="cyanogenmod.permission.MANAGE_ALARMS" />
|
||||||
|
@ -21,6 +21,10 @@
|
||||||
<uses-permission android:name="cyanogenmod.permission.MODIFY_PROFILES" />
|
<uses-permission android:name="cyanogenmod.permission.MODIFY_PROFILES" />
|
||||||
<uses-permission android:name="cyanogenmod.permission.MANAGE_PERSISTENT_STORAGE" />
|
<uses-permission android:name="cyanogenmod.permission.MANAGE_PERSISTENT_STORAGE" />
|
||||||
<uses-permission android:name="cyanogenmod.permission.PERFORMANCE_ACCESS" />
|
<uses-permission android:name="cyanogenmod.permission.PERFORMANCE_ACCESS" />
|
||||||
|
<uses-permission android:name="cyanogenmod.permission.READ_THEMES" />
|
||||||
|
<uses-permission android:name="cyanogenmod.permission.WRITE_THEMES" />
|
||||||
|
<uses-permission android:name="cyanogenmod.permission.ACCESS_THEME_MANAGER" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
|
<uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
|
||||||
|
|
||||||
<application android:name=".CyanogenModTestApplication"
|
<application android:name=".CyanogenModTestApplication"
|
||||||
|
|
|
@ -0,0 +1,354 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2016 The CyanogenMod 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 org.cyanogenmod.tests.themes.unit;
|
||||||
|
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.test.AndroidTestCase;
|
||||||
|
import android.test.suitebuilder.annotation.SmallTest;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import cyanogenmod.themes.IThemeService;
|
||||||
|
import cyanogenmod.themes.ThemeChangeRequest;
|
||||||
|
import cyanogenmod.themes.ThemeManager;
|
||||||
|
import cyanogenmod.themes.ThemeManager.ThemeChangeListener;
|
||||||
|
|
||||||
|
import cyanogenmod.providers.CMSettings;
|
||||||
|
import cyanogenmod.providers.ThemesContract;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
|
public class ThemeManagerTest extends AndroidTestCase {
|
||||||
|
private static final String TAG = ThemeManagerTest.class.getSimpleName();
|
||||||
|
private static final int COUNTDOWN = 1;
|
||||||
|
|
||||||
|
private ThemeManager mThemeManager;
|
||||||
|
private ContentResolver mContentResolver;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
mThemeManager = ThemeManager.getInstance(getContext());
|
||||||
|
mContentResolver = mContext.getContentResolver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public void testManagerExists() {
|
||||||
|
assertNotNull(mThemeManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public void testManagerServiceIsAvailable() {
|
||||||
|
IThemeService icmStatusBarManager = mThemeManager.getService();
|
||||||
|
assertNotNull(icmStatusBarManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public void testApplyDefaultTheme() {
|
||||||
|
final HashMap<String, String> componentKeyMap = new HashMap<>();
|
||||||
|
final CountDownLatch signal = new CountDownLatch(COUNTDOWN);
|
||||||
|
|
||||||
|
// Get the default theme package
|
||||||
|
final String defaultThemePkg = CMSettings.Secure.getString(mContentResolver,
|
||||||
|
CMSettings.Secure.DEFAULT_THEME_PACKAGE);
|
||||||
|
|
||||||
|
// Get the deefault theme components
|
||||||
|
final ArrayList<String> components = new ArrayList<>(
|
||||||
|
Arrays.asList(CMSettings.Secure.getString(mContentResolver,
|
||||||
|
CMSettings.Secure.DEFAULT_THEME_COMPONENTS).split("\\|")));
|
||||||
|
|
||||||
|
// Populate componentkey map since we're going to lock the thread
|
||||||
|
for (String component : components) {
|
||||||
|
String key = ThemesContract.MixnMatchColumns.componentToMixNMatchKey(component);
|
||||||
|
componentKeyMap.put(key, getPackageNameForKey(mContext, key));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register defaultThemeChangeListener
|
||||||
|
mThemeManager.registerThemeChangeListener(new ThemeChangeListener() {
|
||||||
|
public void onProgress(int progress) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onFinish(boolean isSuccess) {
|
||||||
|
boolean assertionFailure = false;
|
||||||
|
if (isSuccess) {
|
||||||
|
for (String component : components) {
|
||||||
|
String key = ThemesContract.MixnMatchColumns.
|
||||||
|
componentToMixNMatchKey(component);
|
||||||
|
Log.d(TAG, "Verifying row " + key);
|
||||||
|
if (!verifyThemeAppliedFromPackageForRow(defaultThemePkg,
|
||||||
|
componentKeyMap.get(key), true)) {
|
||||||
|
Log.d(TAG, "Expected package " + defaultThemePkg
|
||||||
|
+ " but got package " + componentKeyMap.get(key));
|
||||||
|
assertionFailure = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mThemeManager.unregisterThemeChangeListener(this);
|
||||||
|
signal.countDown();
|
||||||
|
if (assertionFailure) throw new AssertionError("Unable to apply default theme");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Apply the default theme
|
||||||
|
mThemeManager.applyDefaultTheme();
|
||||||
|
|
||||||
|
// Lock
|
||||||
|
try {
|
||||||
|
signal.await();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ThemeChangeListener dummyThemeChangeListener = new ThemeChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onProgress(int progress) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFinish(boolean isSuccess) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public void testRegisterAndUnregisterThemeChangeListener() {
|
||||||
|
// Exploit the illegalArgumentException thrown by registerThemeChangeListener to
|
||||||
|
// verify registration.
|
||||||
|
mThemeManager.registerThemeChangeListener(dummyThemeChangeListener);
|
||||||
|
|
||||||
|
try {
|
||||||
|
mThemeManager.registerThemeChangeListener(dummyThemeChangeListener);
|
||||||
|
throw new AssertionError("Failed to register theme change listener!");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// EXPECTED!
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inversely, exploit that the illegal argument exception isn't thrown
|
||||||
|
// if unregistering and reregistering
|
||||||
|
mThemeManager.unregisterThemeChangeListener(dummyThemeChangeListener);
|
||||||
|
|
||||||
|
try {
|
||||||
|
mThemeManager.registerThemeChangeListener(dummyThemeChangeListener);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new AssertionError("Failed to unregister theme change listener!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup!
|
||||||
|
mThemeManager.unregisterThemeChangeListener(dummyThemeChangeListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ThemeManager.ThemeProcessingListener dummyThemeProcessingListener =
|
||||||
|
new ThemeManager.ThemeProcessingListener() {
|
||||||
|
@Override
|
||||||
|
public void onFinishedProcessing(String pkgName) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public void testRegisterAndUnregisterThemeProcessingListener() {
|
||||||
|
// Exploit the illegalArgumentException thrown by registerThemeChangeListener to
|
||||||
|
// verify registration.
|
||||||
|
mThemeManager.registerProcessingListener(dummyThemeProcessingListener);
|
||||||
|
|
||||||
|
try {
|
||||||
|
mThemeManager.registerProcessingListener(dummyThemeProcessingListener);
|
||||||
|
throw new AssertionError("Failed to register theme processing listener!");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// EXPECTED!
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inversely, exploit that the illegal argument exception isn't thrown
|
||||||
|
// if unregistering and reregistering
|
||||||
|
mThemeManager.unregisterProcessingListener(dummyThemeProcessingListener);
|
||||||
|
|
||||||
|
try {
|
||||||
|
mThemeManager.registerProcessingListener(dummyThemeProcessingListener);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new AssertionError("Failed to unregister theme change listener!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup!
|
||||||
|
mThemeManager.unregisterProcessingListener(dummyThemeProcessingListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean actualRequestThemeChangeAsMapResponse = false;
|
||||||
|
@SmallTest
|
||||||
|
public void testRequestThemeChangeAsMapAndCallback() {
|
||||||
|
Map<String, String> expectedAppOverlayMap = new HashMap<>();
|
||||||
|
final CountDownLatch signal = new CountDownLatch(COUNTDOWN);
|
||||||
|
|
||||||
|
// Get the deefault theme components
|
||||||
|
final ArrayList<String> components = new ArrayList<>(
|
||||||
|
Arrays.asList(CMSettings.Secure.getString(mContentResolver,
|
||||||
|
CMSettings.Secure.DEFAULT_THEME_COMPONENTS).split("\\|")));
|
||||||
|
|
||||||
|
// Get the default theme package
|
||||||
|
final String defaultThemePkg = CMSettings.Secure.getString(mContentResolver,
|
||||||
|
CMSettings.Secure.DEFAULT_THEME_PACKAGE);
|
||||||
|
|
||||||
|
for (String component : components) {
|
||||||
|
expectedAppOverlayMap.put(component, defaultThemePkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
mThemeManager.registerThemeChangeListener(new ThemeChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onProgress(int progress) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFinish(boolean isSuccess) {
|
||||||
|
actualRequestThemeChangeAsMapResponse = isSuccess;
|
||||||
|
signal.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mThemeManager.requestThemeChange(expectedAppOverlayMap);
|
||||||
|
|
||||||
|
// Lock
|
||||||
|
try {
|
||||||
|
signal.await();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue(actualRequestThemeChangeAsMapResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean actualRequestThemeChangeAsStringListResponse = false;
|
||||||
|
@SmallTest
|
||||||
|
public void testRequestThemeChangeAsStringListAndCallback() {
|
||||||
|
final CountDownLatch signal = new CountDownLatch(COUNTDOWN);
|
||||||
|
|
||||||
|
// Get the deefault theme components
|
||||||
|
final ArrayList<String> components = new ArrayList<>(
|
||||||
|
Arrays.asList(CMSettings.Secure.getString(mContentResolver,
|
||||||
|
CMSettings.Secure.DEFAULT_THEME_COMPONENTS).split("\\|")));
|
||||||
|
|
||||||
|
// Get the default theme package
|
||||||
|
final String defaultThemePkg = CMSettings.Secure.getString(mContentResolver,
|
||||||
|
CMSettings.Secure.DEFAULT_THEME_PACKAGE);
|
||||||
|
|
||||||
|
mThemeManager.registerThemeChangeListener(new ThemeChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onProgress(int progress) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFinish(boolean isSuccess) {
|
||||||
|
actualRequestThemeChangeAsStringListResponse = isSuccess;
|
||||||
|
signal.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mThemeManager.requestThemeChange(defaultThemePkg, components);
|
||||||
|
|
||||||
|
// Lock
|
||||||
|
try {
|
||||||
|
signal.await();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue(actualRequestThemeChangeAsStringListResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean actualRequestThemeChangeAsRequestResponse = false;
|
||||||
|
@SmallTest
|
||||||
|
public void testRequestThemeChangeAsRequestAndCallback() {
|
||||||
|
final CountDownLatch signal = new CountDownLatch(COUNTDOWN);
|
||||||
|
|
||||||
|
// Get the default theme package
|
||||||
|
final String defaultThemePkg = CMSettings.Secure.getString(mContentResolver,
|
||||||
|
CMSettings.Secure.DEFAULT_THEME_PACKAGE);
|
||||||
|
|
||||||
|
ThemeChangeRequest request = new ThemeChangeRequest.Builder()
|
||||||
|
.setAlarm(defaultThemePkg)
|
||||||
|
.setNavBar(defaultThemePkg)
|
||||||
|
.setBootanimation(defaultThemePkg)
|
||||||
|
.setLockWallpaper(defaultThemePkg)
|
||||||
|
.setLiveLockScreen(defaultThemePkg)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
mThemeManager.registerThemeChangeListener(new ThemeChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onProgress(int progress) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFinish(boolean isSuccess) {
|
||||||
|
actualRequestThemeChangeAsRequestResponse = isSuccess;
|
||||||
|
signal.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mThemeManager.requestThemeChange(request, true);
|
||||||
|
|
||||||
|
// Lock
|
||||||
|
try {
|
||||||
|
signal.await();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue(actualRequestThemeChangeAsRequestResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean verifyThemeAppliedFromPackageForRow(String packageName, String expectedPackage,
|
||||||
|
boolean systemTheme) {
|
||||||
|
boolean verified = TextUtils.isEmpty(expectedPackage) ||
|
||||||
|
TextUtils.equals(packageName, expectedPackage);
|
||||||
|
|
||||||
|
if (systemTheme && !verified) {
|
||||||
|
verified = TextUtils.equals(expectedPackage, "system");
|
||||||
|
}
|
||||||
|
|
||||||
|
return verified;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPackageNameForKey(Context context, String key) {
|
||||||
|
final ContentResolver cr = context.getContentResolver();
|
||||||
|
String[] projection = {ThemesContract.MixnMatchColumns.COL_VALUE};
|
||||||
|
String selection = ThemesContract.MixnMatchColumns.COL_KEY + "=?";
|
||||||
|
String[] selectionArgs = {key};
|
||||||
|
Cursor c = cr.query(ThemesContract.MixnMatchColumns.CONTENT_URI, projection, selection,
|
||||||
|
selectionArgs, null, null);
|
||||||
|
if (c != null) {
|
||||||
|
try {
|
||||||
|
if (c.moveToFirst()) {
|
||||||
|
return c.getString(0);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
c.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue