Enable Window Manager to store app-specific locales and apply them.

Test: atest WmTests:ActivityTaskManagerServiceTests

Bug: 194095029
Bug: 194369257
Bug: 194369420
Bug: 194369426
Bug: 194370141

Change-Id: I743a9cfb84f4b054caa03413f39671d3f43a81c4
This commit is contained in:
“riyaghai”
2021-09-09 03:55:07 +00:00
parent 4fba1c4453
commit 2277de9765
8 changed files with 461 additions and 27 deletions

View File

@@ -30,6 +30,7 @@ import android.content.pm.ApplicationInfo;
import android.content.res.CompatibilityInfo;
import android.os.Bundle;
import android.os.IBinder;
import android.os.LocaleList;
import android.os.RemoteException;
import android.service.voice.IVoiceInteractionSession;
import android.util.IntArray;
@@ -610,6 +611,14 @@ public abstract class ActivityTaskManagerInternal {
*/
PackageConfigurationUpdater setNightMode(int nightMode);
/**
* Sets the app-specific locales for the application referenced by this updater.
* This setting is persisted and will overlay on top of the system locales for
* the said application.
* @return the current {@link PackageConfigurationUpdater} updated with the provided locale.
*/
PackageConfigurationUpdater setLocales(LocaleList locales);
/**
* Commit changes.
*/

View File

@@ -947,7 +947,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
setRecentTasks(new RecentTasks(this, mTaskSupervisor));
mVrController = new VrController(mGlobalLock);
mKeyguardController = mTaskSupervisor.getKeyguardController();
mPackageConfigPersister = new PackageConfigPersister(mTaskSupervisor.mPersisterQueue);
mPackageConfigPersister = new PackageConfigPersister(mTaskSupervisor.mPersisterQueue, this);
}
public void onActivityManagerInternalAdded() {
@@ -6519,7 +6519,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
final class PackageConfigurationUpdaterImpl implements
ActivityTaskManagerInternal.PackageConfigurationUpdater {
private final int mPid;
private int mNightMode;
private Integer mNightMode;
private LocaleList mLocales;
PackageConfigurationUpdaterImpl(int pid) {
mPid = pid;
@@ -6531,6 +6532,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return this;
}
@Override
public ActivityTaskManagerInternal.PackageConfigurationUpdater
setLocales(LocaleList locales) {
mLocales = locales;
return this;
}
@Override
public void commit() {
synchronized (mGlobalLock) {
@@ -6541,8 +6549,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
Slog.w(TAG, "Override application configuration: cannot find pid " + mPid);
return;
}
wpc.setOverrideNightMode(mNightMode);
wpc.updateNightModeForAllActivities(mNightMode);
LocaleList localesOverride = LocaleOverlayHelper.combineLocalesIfOverlayExists(
mLocales, getGlobalConfiguration().getLocales());
wpc.applyAppSpecificConfig(mNightMode, localesOverride);
wpc.updateAppSpecificSettingsForAllActivities(mNightMode, localesOverride);
mPackageConfigPersister.updateFromImpl(wpc.mName, wpc.mUserId, this);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -6550,8 +6560,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
}
int getNightMode() {
Integer getNightMode() {
return mNightMode;
}
LocaleList getLocales() {
return mLocales;
}
}
}

View File

@@ -39,6 +39,7 @@ import android.app.WindowConfiguration;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.LocaleList;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
@@ -512,7 +513,7 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
return mFullConfiguration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_FREEFORM;
}
/** Returns the activity type associated with the the configuration container. */
/** Returns the activity type associated with the configuration container. */
/*@WindowConfiguration.ActivityType*/
public int getActivityType() {
return mFullConfiguration.windowConfiguration.getActivityType();
@@ -545,21 +546,49 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
return getActivityType() == ACTIVITY_TYPE_ASSISTANT;
}
/**
* Applies app-specific nightMode and {@link LocaleList} on requested configuration.
* @return true if any of the requested configuration has been updated.
*/
public boolean applyAppSpecificConfig(Integer nightMode, LocaleList locales) {
mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
boolean newNightModeSet = (nightMode != null) && setOverrideNightMode(mRequestsTmpConfig,
nightMode);
boolean newLocalesSet = (locales != null) && setOverrideLocales(mRequestsTmpConfig,
locales);
if (newNightModeSet || newLocalesSet) {
onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
}
return newNightModeSet || newLocalesSet;
}
/**
* Overrides the night mode applied to this ConfigurationContainer.
* @return true if the nightMode has been changed.
*/
public boolean setOverrideNightMode(int nightMode) {
private boolean setOverrideNightMode(Configuration requestsTmpConfig, int nightMode) {
final int currentUiMode = mRequestedOverrideConfiguration.uiMode;
final int currentNightMode = currentUiMode & Configuration.UI_MODE_NIGHT_MASK;
final int validNightMode = nightMode & Configuration.UI_MODE_NIGHT_MASK;
if (currentNightMode == validNightMode) {
return false;
}
mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
mRequestsTmpConfig.uiMode = validNightMode
requestsTmpConfig.uiMode = validNightMode
| (currentUiMode & ~Configuration.UI_MODE_NIGHT_MASK);
onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
return true;
}
/**
* Overrides the locales applied to this ConfigurationContainer.
* @return true if the LocaleList has been changed.
*/
private boolean setOverrideLocales(Configuration requestsTmpConfig,
@NonNull LocaleList overrideLocales) {
if (mRequestedOverrideConfiguration.getLocales().equals(overrideLocales)) {
return false;
}
requestsTmpConfig.setLocales(overrideLocales);
requestsTmpConfig.userSetLocale = true;
return true;
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2021 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.wm;
import android.os.LocaleList;
import java.util.Locale;
/**
* Static utilities to overlay locales on top of another localeList.
*
* <p>This is used to overlay application-specific locales in
* {@link com.android.server.wm.ActivityTaskManagerInternal.PackageConfigurationUpdater} on top of
* system locales.
*/
final class LocaleOverlayHelper {
/**
* Combines the overlay locales and base locales.
* @return the combined {@link LocaleList} if the overlay locales is not empty/null else
* returns the empty/null LocaleList.
*/
static LocaleList combineLocalesIfOverlayExists(LocaleList overlayLocales,
LocaleList baseLocales) {
if (overlayLocales == null || overlayLocales.isEmpty()) {
return overlayLocales;
}
return combineLocales(overlayLocales, baseLocales);
}
/**
* Creates a combined {@link LocaleList} by placing overlay locales before base locales and
* dropping duplicates from the base locales.
*/
private static LocaleList combineLocales(LocaleList overlayLocales, LocaleList baseLocales) {
Locale[] combinedLocales = new Locale[overlayLocales.size() + baseLocales.size()];
for (int i = 0; i < overlayLocales.size(); i++) {
combinedLocales[i] = overlayLocales.get(i);
}
for (int i = 0; i < baseLocales.size(); i++) {
combinedLocales[i + overlayLocales.size()] = baseLocales.get(i);
}
// Constructor of {@link LocaleList} removes duplicates
return new LocaleList(combinedLocales);
}
}

View File

@@ -21,6 +21,7 @@ import static android.app.UiModeManager.MODE_NIGHT_CUSTOM;
import android.annotation.NonNull;
import android.os.Environment;
import android.os.LocaleList;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
@@ -54,12 +55,14 @@ public class PackageConfigPersister {
private static final String TAG_CONFIG = "config";
private static final String ATTR_PACKAGE_NAME = "package_name";
private static final String ATTR_NIGHT_MODE = "night_mode";
private static final String ATTR_LOCALES = "locale_list";
private static final String PACKAGE_DIRNAME = "package_configs";
private static final String SUFFIX_FILE_NAME = "_config.xml";
private final PersisterQueue mPersisterQueue;
private final Object mLock = new Object();
private final ActivityTaskManagerService mAtm;
@GuardedBy("mLock")
private final SparseArray<HashMap<String, PackageConfigRecord>> mPendingWrite =
@@ -72,8 +75,9 @@ public class PackageConfigPersister {
return new File(Environment.getDataSystemCeDirectory(userId), PACKAGE_DIRNAME);
}
PackageConfigPersister(PersisterQueue queue) {
PackageConfigPersister(PersisterQueue queue, ActivityTaskManagerService atm) {
mPersisterQueue = queue;
mAtm = atm;
}
@GuardedBy("mLock")
@@ -100,7 +104,8 @@ public class PackageConfigPersister {
final TypedXmlPullParser in = Xml.resolvePullParser(is);
int event;
String packageName = null;
int nightMode = MODE_NIGHT_AUTO;
Integer nightMode = null;
LocaleList locales = null;
while (((event = in.next()) != XmlPullParser.END_DOCUMENT)
&& event != XmlPullParser.END_TAG) {
final String name = in.getName();
@@ -120,6 +125,9 @@ public class PackageConfigPersister {
case ATTR_NIGHT_MODE:
nightMode = Integer.parseInt(attrValue);
break;
case ATTR_LOCALES:
locales = LocaleList.forLanguageTags(attrValue);
break;
}
}
}
@@ -130,6 +138,7 @@ public class PackageConfigPersister {
final PackageConfigRecord initRecord =
findRecordOrCreate(mModified, packageName, userId);
initRecord.mNightMode = nightMode;
initRecord.mLocales = locales;
if (DEBUG) {
Slog.d(TAG, "loadPackages: load one package " + initRecord);
}
@@ -155,7 +164,9 @@ public class PackageConfigPersister {
"updateConfigIfNeeded record " + container + " find? " + modifiedRecord);
}
if (modifiedRecord != null) {
container.setOverrideNightMode(modifiedRecord.mNightMode);
container.applyAppSpecificConfig(modifiedRecord.mNightMode,
LocaleOverlayHelper.combineLocalesIfOverlayExists(
modifiedRecord.mLocales, mAtm.getGlobalConfiguration().getLocales()));
}
}
}
@@ -165,10 +176,16 @@ public class PackageConfigPersister {
ActivityTaskManagerService.PackageConfigurationUpdaterImpl impl) {
synchronized (mLock) {
PackageConfigRecord record = findRecordOrCreate(mModified, packageName, userId);
record.mNightMode = impl.getNightMode();
if (record.isResetNightMode()) {
removePackage(record.mName, record.mUserId);
if (impl.getNightMode() != null) {
record.mNightMode = impl.getNightMode();
}
if (impl.getLocales() != null) {
record.mLocales = impl.getLocales();
}
if ((record.mNightMode == null || record.isResetNightMode())
&& (record.mLocales == null || record.mLocales.isEmpty())) {
// if all values default to system settings, we can remove the package.
removePackage(packageName, userId);
} else {
final PackageConfigRecord pendingRecord =
findRecord(mPendingWrite, record.mName, record.mUserId);
@@ -179,10 +196,11 @@ public class PackageConfigPersister {
} else {
writeRecord = pendingRecord;
}
if (writeRecord.mNightMode == record.mNightMode) {
if (!updateNightMode(record, writeRecord) && !updateLocales(record, writeRecord)) {
return;
}
writeRecord.mNightMode = record.mNightMode;
if (DEBUG) {
Slog.d(TAG, "PackageConfigUpdater save config " + writeRecord);
}
@@ -191,6 +209,22 @@ public class PackageConfigPersister {
}
}
private boolean updateNightMode(PackageConfigRecord record, PackageConfigRecord writeRecord) {
if (record.mNightMode == null || record.mNightMode.equals(writeRecord.mNightMode)) {
return false;
}
writeRecord.mNightMode = record.mNightMode;
return true;
}
private boolean updateLocales(PackageConfigRecord record, PackageConfigRecord writeRecord) {
if (record.mLocales == null || record.mLocales.equals(writeRecord.mLocales)) {
return false;
}
writeRecord.mLocales = record.mLocales;
return true;
}
@GuardedBy("mLock")
void removeUser(int userId) {
synchronized (mLock) {
@@ -210,7 +244,7 @@ public class PackageConfigPersister {
@GuardedBy("mLock")
void onPackageUninstall(String packageName) {
synchronized (mLock) {
for (int i = mModified.size() - 1; i > 0; i--) {
for (int i = mModified.size() - 1; i >= 0; i--) {
final int userId = mModified.keyAt(i);
removePackage(packageName, userId);
}
@@ -242,7 +276,8 @@ public class PackageConfigPersister {
static class PackageConfigRecord {
final String mName;
final int mUserId;
int mNightMode;
Integer mNightMode;
LocaleList mLocales;
PackageConfigRecord(String name, int userId) {
mName = name;
@@ -256,7 +291,7 @@ public class PackageConfigPersister {
@Override
public String toString() {
return "PackageConfigRecord package name: " + mName + " userId " + mUserId
+ " nightMode " + mNightMode;
+ " nightMode " + mNightMode + " locales " + mLocales;
}
}
@@ -369,7 +404,13 @@ public class PackageConfigPersister {
}
xmlSerializer.startTag(null, TAG_CONFIG);
xmlSerializer.attribute(null, ATTR_PACKAGE_NAME, mRecord.mName);
xmlSerializer.attributeInt(null, ATTR_NIGHT_MODE, mRecord.mNightMode);
if (mRecord.mNightMode != null) {
xmlSerializer.attributeInt(null, ATTR_NIGHT_MODE, mRecord.mNightMode);
}
if (mRecord.mLocales != null) {
xmlSerializer.attribute(null, ATTR_LOCALES, mRecord.mLocales
.toLanguageTags());
}
xmlSerializer.endTag(null, TAG_CONFIG);
xmlSerializer.endDocument();
xmlSerializer.flush();

View File

@@ -57,6 +57,7 @@ import android.content.res.Configuration;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.os.LocaleList;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
@@ -817,10 +818,13 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
return false;
}
void updateNightModeForAllActivities(int nightMode) {
// TODO(b/199277065): Re-assess how app-specific locales are applied based on UXR
// TODO(b/199277729): Consider whether we need to add special casing for edge cases like
// activity-embeddings etc.
void updateAppSpecificSettingsForAllActivities(Integer nightMode, LocaleList localesOverride) {
for (int i = mActivities.size() - 1; i >= 0; --i) {
final ActivityRecord r = mActivities.get(i);
if (r.setOverrideNightMode(nightMode) && r.mVisibleRequested) {
if (r.applyAppSpecificConfig(nightMode, localesOverride) && r.mVisibleRequested) {
r.ensureActivityConfiguration(0 /* globalChanges */, true /* preserveWindow */);
}
}

View File

@@ -43,13 +43,17 @@ import static org.mockito.Mockito.when;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.IApplicationThread;
import android.app.PictureInPictureParams;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.EnterPipRequestedItem;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.os.LocaleList;
import android.os.PowerManager;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
@@ -61,6 +65,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.mockito.MockitoSession;
import java.util.ArrayList;
@@ -80,6 +85,9 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase {
private final ArgumentCaptor<ClientTransaction> mClientTransactionCaptor =
ArgumentCaptor.forClass(ClientTransaction.class);
private static final String DEFAULT_PACKAGE_NAME = "my.application.package";
private static final int DEFAULT_USER_ID = 100;
@Before
public void setUp() throws Exception {
setBooted(mAtm);
@@ -480,5 +488,269 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase {
assertTrue(activity.supportsMultiWindow());
assertTrue(task.supportsMultiWindow());
}
@Test
public void testPackageConfigUpdate_locales_successfullyApplied() {
Configuration config = mAtm.getGlobalConfiguration();
config.setLocales(LocaleList.forLanguageTags("en-XC"));
mAtm.updateGlobalConfigurationLocked(config, true, true, DEFAULT_USER_ID);
mAtm.mProcessMap.put(Binder.getCallingPid(), createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID));
ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater =
mAtm.mInternal.createPackageConfigurationUpdater();
packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB")).commit();
WindowProcessController wpcAfterConfigChange = createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"),
wpcAfterConfigChange.getConfiguration().getLocales());
assertFalse(wpcAfterConfigChange.getConfiguration().isNightModeActive());
}
@Test
public void testPackageConfigUpdate_nightMode_successfullyApplied() {
Configuration config = mAtm.getGlobalConfiguration();
config.setLocales(LocaleList.forLanguageTags("en-XC"));
mAtm.updateGlobalConfigurationLocked(config, true, true, DEFAULT_USER_ID);
mAtm.mProcessMap.put(Binder.getCallingPid(), createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID));
ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater =
mAtm.mInternal.createPackageConfigurationUpdater();
packageConfigUpdater.setNightMode(Configuration.UI_MODE_NIGHT_YES).commit();
WindowProcessController wpcAfterConfigChange = createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
assertTrue(wpcAfterConfigChange.getConfiguration().isNightModeActive());
assertEquals(LocaleList.forLanguageTags("en-XC"),
wpcAfterConfigChange.getConfiguration().getLocales());
}
@Test
public void testPackageConfigUpdate_multipleLocaleUpdates_successfullyApplied() {
Configuration config = mAtm.getGlobalConfiguration();
config.setLocales(LocaleList.forLanguageTags("en-XC"));
mAtm.updateGlobalConfigurationLocked(config, true, true, DEFAULT_USER_ID);
WindowProcessController wpc = createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
mAtm.mProcessMap.put(Binder.getCallingPid(), wpc);
ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater =
mAtm.mInternal.createPackageConfigurationUpdater();
packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB"))
.setNightMode(Configuration.UI_MODE_NIGHT_YES).commit();
WindowProcessController wpcAfterConfigChange1 = createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"),
wpcAfterConfigChange1.getConfiguration().getLocales());
assertTrue(wpcAfterConfigChange1.getConfiguration().isNightModeActive());
assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"),
wpc.getConfiguration().getLocales());
packageConfigUpdater.setLocales(LocaleList.forLanguageTags("ja-XC,en-XC")).commit();
WindowProcessController wpcAfterConfigChange2 = createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
assertEquals(LocaleList.forLanguageTags("ja-XC,en-XC"),
wpcAfterConfigChange2.getConfiguration().getLocales());
assertTrue(wpcAfterConfigChange1.getConfiguration().isNightModeActive());
assertEquals(LocaleList.forLanguageTags("ja-XC,en-XC"),
wpc.getConfiguration().getLocales());
}
@Test
public void testPackageConfigUpdate_multipleNightModeUpdates_successfullyApplied() {
Configuration config = mAtm.getGlobalConfiguration();
config.setLocales(LocaleList.forLanguageTags("en-XC"));
mAtm.updateGlobalConfigurationLocked(config, true, true, DEFAULT_USER_ID);
mAtm.mProcessMap.put(Binder.getCallingPid(), createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID));
ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater =
mAtm.mInternal.createPackageConfigurationUpdater();
packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB"))
.setNightMode(Configuration.UI_MODE_NIGHT_YES).commit();
WindowProcessController wpcAfterConfigChange1 = createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"),
wpcAfterConfigChange1.getConfiguration().getLocales());
assertTrue(wpcAfterConfigChange1.getConfiguration().isNightModeActive());
packageConfigUpdater.setNightMode(Configuration.UI_MODE_NIGHT_NO).commit();
WindowProcessController wpcAfterConfigChange2 = createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"),
wpcAfterConfigChange2.getConfiguration().getLocales());
assertFalse(wpcAfterConfigChange2.getConfiguration().isNightModeActive());
}
@Test
public void testPackageConfigUpdate_onPackageUninstall_configShouldNotApply() {
Configuration config = mAtm.getGlobalConfiguration();
config.setLocales(LocaleList.forLanguageTags("en-XC"));
mAtm.updateGlobalConfigurationLocked(config, true, true, DEFAULT_USER_ID);
mAtm.mProcessMap.put(Binder.getCallingPid(), createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID));
ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater =
mAtm.mInternal.createPackageConfigurationUpdater();
packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB"))
.setNightMode(Configuration.UI_MODE_NIGHT_YES).commit();
WindowProcessController wpcAfterConfigChange1 = createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"),
wpcAfterConfigChange1.getConfiguration().getLocales());
assertTrue(wpcAfterConfigChange1.getConfiguration().isNightModeActive());
mAtm.mInternal.onPackageUninstalled(DEFAULT_PACKAGE_NAME);
WindowProcessController wpcAfterConfigChange2 = createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
assertEquals(LocaleList.forLanguageTags("en-XC"),
wpcAfterConfigChange2.getConfiguration().getLocales());
assertFalse(wpcAfterConfigChange2.getConfiguration().isNightModeActive());
}
@Test
public void testPackageConfigUpdate_LocalesEmptyAndNightModeUndefined_configShouldNotApply() {
Configuration config = mAtm.getGlobalConfiguration();
config.setLocales(LocaleList.forLanguageTags("en-XC"));
mAtm.updateGlobalConfigurationLocked(config, true, true, DEFAULT_USER_ID);
WindowProcessController wpc = createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
mAtm.mProcessMap.put(Binder.getCallingPid(), wpc);
ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater =
mAtm.mInternal.createPackageConfigurationUpdater();
packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB"))
.setNightMode(Configuration.UI_MODE_NIGHT_YES).commit();
WindowProcessController wpcAfterConfigChange1 = createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"),
wpcAfterConfigChange1.getConfiguration().getLocales());
assertTrue(wpcAfterConfigChange1.getConfiguration().isNightModeActive());
assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"),
wpc.getConfiguration().getLocales());
packageConfigUpdater.setLocales(LocaleList.getEmptyLocaleList())
.setNightMode(Configuration.UI_MODE_NIGHT_UNDEFINED).commit();
WindowProcessController wpcAfterConfigChange2 = createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
assertEquals(LocaleList.forLanguageTags("en-XC"),
wpcAfterConfigChange2.getConfiguration().getLocales());
assertFalse(wpcAfterConfigChange2.getConfiguration().isNightModeActive());
assertEquals(LocaleList.forLanguageTags("en-XC"),
wpc.getConfiguration().getLocales());
}
@Test
public void testPackageConfigUpdate_WhenUserRemoved_configShouldNotApply() {
Configuration config = mAtm.getGlobalConfiguration();
config.setLocales(LocaleList.forLanguageTags("en-XC"));
mAtm.updateGlobalConfigurationLocked(config, true, true, DEFAULT_USER_ID);
mAtm.mProcessMap.put(Binder.getCallingPid(), createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID));
ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater =
mAtm.mInternal.createPackageConfigurationUpdater();
packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB"))
.setNightMode(Configuration.UI_MODE_NIGHT_YES).commit();
WindowProcessController wpcAfterConfigChange1 = createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"),
wpcAfterConfigChange1.getConfiguration().getLocales());
assertTrue(wpcAfterConfigChange1.getConfiguration().isNightModeActive());
mAtm.mInternal.removeUser(DEFAULT_USER_ID);
WindowProcessController wpcAfterConfigChange2 = createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
assertEquals(LocaleList.forLanguageTags("en-XC"),
wpcAfterConfigChange2.getConfiguration().getLocales());
assertFalse(wpcAfterConfigChange2.getConfiguration().isNightModeActive());
}
@Test
public void testPackageConfigUpdate_setLocaleListToEmpty_doesNotOverlayLocaleListInWpc() {
Configuration config = mAtm.getGlobalConfiguration();
config.setLocales(LocaleList.forLanguageTags("en-XC"));
mAtm.updateGlobalConfigurationLocked(config, true, true, DEFAULT_USER_ID);
mAtm.mProcessMap.put(Binder.getCallingPid(), createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID));
ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater =
mAtm.mInternal.createPackageConfigurationUpdater();
packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB"))
.setNightMode(Configuration.UI_MODE_NIGHT_YES).commit();
WindowProcessController wpcAfterConfigChange1 = createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"),
wpcAfterConfigChange1.getConfiguration().getLocales());
assertTrue(wpcAfterConfigChange1.getConfiguration().isNightModeActive());
packageConfigUpdater.setLocales(LocaleList.getEmptyLocaleList()).commit();
WindowProcessController wpcAfterConfigChange2 = createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
assertEquals(LocaleList.forLanguageTags("en-XC"),
wpcAfterConfigChange2.getConfiguration().getLocales());
assertTrue(wpcAfterConfigChange2.getConfiguration().isNightModeActive());
}
@Test
public void testPackageConfigUpdate_resetNightMode_doesNotOverrideNightModeInWpc() {
Configuration config = mAtm.getGlobalConfiguration();
config.setLocales(LocaleList.forLanguageTags("en-XC"));
mAtm.updateGlobalConfigurationLocked(config, true, true, DEFAULT_USER_ID);
mAtm.mProcessMap.put(Binder.getCallingPid(), createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID));
ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater =
mAtm.mInternal.createPackageConfigurationUpdater();
packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB"))
.setNightMode(Configuration.UI_MODE_NIGHT_YES).commit();
WindowProcessController wpcAfterConfigChange1 = createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"),
wpcAfterConfigChange1.getConfiguration().getLocales());
assertTrue(wpcAfterConfigChange1.getConfiguration().isNightModeActive());
packageConfigUpdater.setNightMode(Configuration.UI_MODE_NIGHT_UNDEFINED).commit();
WindowProcessController wpcAfterConfigChange2 = createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"),
wpcAfterConfigChange2.getConfiguration().getLocales());
assertFalse(wpcAfterConfigChange2.getConfiguration().isNightModeActive());
}
private WindowProcessController createWindowProcessController(String packageName,
int userId) {
WindowProcessListener mMockListener = Mockito.mock(WindowProcessListener.class);
ApplicationInfo info = mock(ApplicationInfo.class);
info.packageName = packageName;
WindowProcessController wpc = new WindowProcessController(
mAtm, info, packageName, 0, userId, null, mMockListener);
wpc.setThread(mock(IApplicationThread.class));
return wpc;
}
}

View File

@@ -34,6 +34,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -49,6 +50,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.LocaleList;
import android.platform.test.annotations.Presubmit;
import org.junit.Before;
@@ -371,8 +373,9 @@ public class WindowProcessControllerTests extends WindowTestsBase {
public void testTopActivityUiModeChangeScheduleConfigChange() {
final ActivityRecord activity = createActivityRecord(mWpc);
activity.mVisibleRequested = true;
doReturn(true).when(activity).setOverrideNightMode(anyInt());
mWpc.updateNightModeForAllActivities(Configuration.UI_MODE_NIGHT_YES);
doReturn(true).when(activity).applyAppSpecificConfig(anyInt(), any());
mWpc.updateAppSpecificSettingsForAllActivities(Configuration.UI_MODE_NIGHT_YES,
LocaleList.forLanguageTags("en-XA"));
verify(activity).ensureActivityConfiguration(anyInt(), anyBoolean());
}