Merge "Fix the system gender in ActivityRecord objects" into main
diff --git a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionBackupHelper.java b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionBackupHelper.java
index d494be5..e91de37 100644
--- a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionBackupHelper.java
+++ b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionBackupHelper.java
@@ -123,8 +123,7 @@
* Returns the system-gender to be backed up as a data-blob.
*/
public byte[] getSystemBackupPayload(int userId) {
- int gender = mGrammaticalGenderService.getSystemGrammaticalGender(mAttributionSource,
- userId);
+ int gender = mGrammaticalGenderService.getSystemGrammaticalGender(userId);
return intToByteArray(gender);
}
@@ -167,7 +166,7 @@
BackupManager.dataChanged(SYSTEM_BACKUP_PACKAGE_KEY);
}
- private byte[] convertToByteArray(HashMap<String, Integer> pkgGenderInfo) {
+ private static byte[] convertToByteArray(HashMap<String, Integer> pkgGenderInfo) {
try (final ByteArrayOutputStream out = new ByteArrayOutputStream();
final ObjectOutputStream objStream = new ObjectOutputStream(out)) {
objStream.writeObject(pkgGenderInfo);
@@ -178,22 +177,22 @@
}
}
- private byte[] intToByteArray(final int gender) {
+ private static byte[] intToByteArray(final int gender) {
ByteBuffer bb = ByteBuffer.allocate(4);
bb.putInt(gender);
return bb.array();
}
- private int convertByteArrayToInt(byte[] intBytes) {
+ private static int convertByteArrayToInt(byte[] intBytes) {
ByteBuffer byteBuffer = ByteBuffer.wrap(intBytes);
return byteBuffer.getInt();
}
- private HashMap<String, Integer> readFromByteArray(byte[] payload) {
+ private static HashMap<String, Integer> readFromByteArray(byte[] payload) {
HashMap<String, Integer> data = new HashMap<>();
- try (ByteArrayInputStream byteIn = new ByteArrayInputStream(payload);
- ObjectInputStream in = new ObjectInputStream(byteIn)) {
+ try (var byteIn = new ByteArrayInputStream(payload);
+ var in = new ObjectInputStream(byteIn)) {
data = (HashMap<String, Integer>) in.readObject();
} catch (IOException | ClassNotFoundException e) {
Log.e(TAG, "cannot convert payload to HashMap.", e);
@@ -205,10 +204,10 @@
private void cleanStagedDataForOldEntries() {
for (int i = 0; i < mCache.size(); i++) {
int userId = mCache.keyAt(i);
- StagedData stagedData = mCache.get(userId);
+ StagedData stagedData = mCache.valueAt(userId);
if (stagedData.mCreationTimeMillis
< mClock.millis() - STAGE_DATA_RETENTION_PERIOD.toMillis()) {
- mCache.remove(userId);
+ mCache.removeAt(i--);
}
}
}
diff --git a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionManagerInternal.java b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionManagerInternal.java
index 2816d08..7eb971c 100644
--- a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionManagerInternal.java
+++ b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionManagerInternal.java
@@ -16,7 +16,6 @@
package com.android.server.grammaticalinflection;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.Configuration;
@@ -41,7 +40,7 @@
public abstract void stageAndApplyRestoredPayload(byte[] payload, int userId);
/**
- * Get the current system grammatical gender of privileged application.
+ * Get the current system grammatical gender for the particular user.
*
* @return the value of grammatical gender
*
@@ -50,18 +49,25 @@
public abstract @Configuration.GrammaticalGender int getSystemGrammaticalGender(int userId);
/**
- * Retrieve the system grammatical gender.
+ * Get the final merged value of the global grammatical gender, user- or devsettings-set.
*
* @return the value of grammatical gender
*
*/
- public abstract @Configuration.GrammaticalGender int retrieveSystemGrammaticalGender(
- @NonNull Configuration configuration);
+ public abstract @Configuration.GrammaticalGender int mergedFinalSystemGrammaticalGender();
+
+ /**
+ * Get the grammatical gender from developer settings global override.
+ *
+ * @return the value of grammatical gender
+ */
+ public abstract
+ @Configuration.GrammaticalGender int getGrammaticalGenderFromDeveloperSettings();
/**
* Whether the package can get the system grammatical gender or not.
*/
- public abstract boolean canGetSystemGrammaticalGender(int uid, @Nullable String packageName);
+ public abstract boolean canGetSystemGrammaticalGender(int uid);
/**
@@ -74,4 +80,3 @@
*/
public abstract void applyRestoredSystemPayload(byte[] payload, int userId);
}
-
diff --git a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
index 93a71b9..e242164 100644
--- a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
+++ b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
@@ -17,7 +17,6 @@
package com.android.server.grammaticalinflection;
import static android.app.Flags.systemTermsOfAddressEnabled;
-import static android.content.res.Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
import static com.android.server.grammaticalinflection.GrammaticalInflectionUtils.checkSystemGrammaticalGenderPermission;
@@ -43,6 +42,7 @@
import android.util.SparseIntArray;
import android.util.Xml;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
@@ -126,7 +126,7 @@
@Override
public void setSystemWideGrammaticalGender(int grammaticalGender, int userId) {
- isCallerAllowed();
+ enforceCallerPermissions();
GrammaticalInflectionService.this.setSystemWideGrammaticalGender(grammaticalGender,
userId);
}
@@ -138,18 +138,16 @@
+ " does not have READ_SYSTEM_GRAMMATICAL_GENDER permission.");
}
return checkSystemTermsOfAddressIsEnabled()
- ? GrammaticalInflectionService.this.getSystemGrammaticalGender(
- attributionSource, userId)
- : GRAMMATICAL_GENDER_NOT_SPECIFIED;
+ ? GrammaticalInflectionService.this.getSystemGrammaticalGender(userId)
+ : Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
}
@Override
public int peekSystemGrammaticalGenderByUserId(AttributionSource attributionSource,
int userId) {
return canGetSystemGrammaticalGender(attributionSource)
- ? GrammaticalInflectionService.this.getSystemGrammaticalGender(
- attributionSource, userId)
- : GRAMMATICAL_GENDER_NOT_SPECIFIED;
+ ? GrammaticalInflectionService.this.getSystemGrammaticalGender(userId)
+ : Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
}
@Override
@@ -163,11 +161,10 @@
private final class GrammaticalInflectionManagerInternalImpl
extends GrammaticalInflectionManagerInternal {
-
@Override
@Nullable
public byte[] getBackupPayload(int userId) {
- isCallerAllowed();
+ enforceCallerPermissions();
return mBackupHelper.getBackupPayload(userId);
}
@@ -179,7 +176,7 @@
@Override
@Nullable
public byte[] getSystemBackupPayload(int userId) {
- isCallerAllowed();
+ enforceCallerPermissions();
return mBackupHelper.getSystemBackupPayload(userId);
}
@@ -191,30 +188,35 @@
@Override
public int getSystemGrammaticalGender(int userId) {
return checkSystemTermsOfAddressIsEnabled()
- ? GrammaticalInflectionService.this.getSystemGrammaticalGender(
- mContext.getAttributionSource(), userId)
- : GRAMMATICAL_GENDER_NOT_SPECIFIED;
+ ? GrammaticalInflectionService.this.getSystemGrammaticalGender(userId)
+ : Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
}
@Override
- public int retrieveSystemGrammaticalGender(Configuration configuration) {
+ public int mergedFinalSystemGrammaticalGender() {
int systemGrammaticalGender = getSystemGrammaticalGender(mContext.getUserId());
// Retrieve the grammatical gender from system property, set it into
// configuration which will get updated later if the grammatical gender raw value of
// current configuration is {@link Configuration#GRAMMATICAL_GENDER_UNDEFINED}.
- if (configuration.getGrammaticalGenderRaw()
- == Configuration.GRAMMATICAL_GENDER_UNDEFINED
- || systemGrammaticalGender <= Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED) {
- systemGrammaticalGender = SystemProperties.getInt(GRAMMATICAL_GENDER_PROPERTY,
- Configuration.GRAMMATICAL_GENDER_UNDEFINED);
+ if (systemGrammaticalGender == Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED) {
+ systemGrammaticalGender = getGrammaticalGenderFromDeveloperSettings();
}
- return systemGrammaticalGender;
+ return systemGrammaticalGender == Configuration.GRAMMATICAL_GENDER_UNDEFINED
+ ? Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED : systemGrammaticalGender;
}
@Override
- public boolean canGetSystemGrammaticalGender(int uid, String packageName) {
- AttributionSource attributionSource = new AttributionSource.Builder(
- uid).setPackageName(packageName).build();
+ public int getGrammaticalGenderFromDeveloperSettings() {
+ return SystemProperties.getInt(GRAMMATICAL_GENDER_PROPERTY,
+ Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED);
+ }
+
+ @Override
+ public boolean canGetSystemGrammaticalGender(int uid) {
+ if (uid == Process.SYSTEM_UID) {
+ return true;
+ }
+ var attributionSource = new AttributionSource.Builder(uid).build();
return GrammaticalInflectionService.this.canGetSystemGrammaticalGender(
attributionSource);
}
@@ -225,7 +227,7 @@
mActivityTaskManagerInternal.getApplicationConfig(appPackageName, userId);
if (appConfig == null || appConfig.mGrammaticalGender == null) {
- return GRAMMATICAL_GENDER_NOT_SPECIFIED;
+ return Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
} else {
return appConfig.mGrammaticalGender;
}
@@ -239,9 +241,10 @@
userId);
if (!SystemProperties.getBoolean(GRAMMATICAL_INFLECTION_ENABLED, true)) {
- if (preValue != GRAMMATICAL_GENDER_NOT_SPECIFIED) {
+ if (preValue != Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED) {
Log.d(TAG, "Clearing the user's grammatical gender setting");
- updater.setGrammaticalGender(GRAMMATICAL_GENDER_NOT_SPECIFIED).commit();
+ updater.setGrammaticalGender(
+ Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED).commit();
}
return;
}
@@ -250,49 +253,48 @@
FrameworkStatsLog.write(FrameworkStatsLog.APPLICATION_GRAMMATICAL_INFLECTION_CHANGED,
FrameworkStatsLog.APPLICATION_GRAMMATICAL_INFLECTION_CHANGED__SOURCE_ID__OTHERS,
uid,
- gender != GRAMMATICAL_GENDER_NOT_SPECIFIED,
- preValue != GRAMMATICAL_GENDER_NOT_SPECIFIED);
+ gender != Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED,
+ preValue != Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED);
updater.setGrammaticalGender(gender).commit();
}
protected void setSystemWideGrammaticalGender(int grammaticalGender, int userId) {
- Trace.beginSection("GrammaticalInflectionService.setSystemWideGrammaticalGender");
- if (!GrammaticalInflectionManager.VALID_GRAMMATICAL_GENDER_VALUES.contains(
- grammaticalGender)) {
- throw new IllegalArgumentException("Unknown grammatical gender");
- }
-
- if (!checkSystemTermsOfAddressIsEnabled()) {
- if (grammaticalGender == GRAMMATICAL_GENDER_NOT_SPECIFIED) {
- return;
+ try {
+ if (!checkSystemTermsOfAddressIsEnabled()) {
+ return; // Nothing to do, and the flag can't get flipped at the runtime.
}
- Log.d(TAG, "Clearing the system grammatical gender setting");
- grammaticalGender = GRAMMATICAL_GENDER_NOT_SPECIFIED;
- }
- synchronized (mLock) {
+ Trace.beginSection("GrammaticalInflectionService.setSystemWideGrammaticalGender");
+ if (!GrammaticalInflectionManager.VALID_GRAMMATICAL_GENDER_VALUES.contains(
+ grammaticalGender)) {
+ throw new IllegalArgumentException("Unknown grammatical gender");
+ }
+
final File file = getGrammaticalGenderFile(userId);
- final AtomicFile atomicFile = new AtomicFile(file);
- FileOutputStream stream = null;
- try {
- stream = atomicFile.startWrite();
- stream.write(toXmlByteArray(grammaticalGender, stream));
- atomicFile.finishWrite(stream);
- mGrammaticalGenderCache.put(userId, grammaticalGender);
- } catch (IOException e) {
- Log.e(TAG, "Failed to write file " + atomicFile, e);
- if (stream != null) {
- atomicFile.failWrite(stream);
+ synchronized (mLock) {
+ final AtomicFile atomicFile = new AtomicFile(file);
+ FileOutputStream stream = null;
+ try {
+ stream = atomicFile.startWrite();
+ stream.write(toXmlByteArray(grammaticalGender, stream));
+ atomicFile.finishWrite(stream);
+ mGrammaticalGenderCache.put(userId, grammaticalGender);
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to write file " + atomicFile, e);
+ if (stream != null) {
+ atomicFile.failWrite(stream);
+ }
+ throw new RuntimeException(e);
}
- throw new RuntimeException(e);
}
+ updateConfiguration(grammaticalGender, userId);
+ } finally {
+ Trace.endSection();
}
- updateConfiguration(grammaticalGender, userId);
- Trace.endSection();
}
- private void updateConfiguration(int grammaticalGender, int userId) {
+ private static void updateConfiguration(int grammaticalGender, int userId) {
try {
Configuration config = new Configuration();
int preValue = config.getGrammaticalGender();
@@ -301,54 +303,47 @@
FrameworkStatsLog.write(FrameworkStatsLog.SYSTEM_GRAMMATICAL_INFLECTION_CHANGED,
FrameworkStatsLog.SYSTEM_GRAMMATICAL_INFLECTION_CHANGED__SOURCE_ID__SYSTEM,
userId,
- grammaticalGender != GRAMMATICAL_GENDER_NOT_SPECIFIED,
- preValue != GRAMMATICAL_GENDER_NOT_SPECIFIED);
+ grammaticalGender != Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED,
+ preValue != Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED);
GrammaticalInflectionBackupHelper.notifyBackupManager();
} catch (RemoteException e) {
Log.w(TAG, "Can not update configuration", e);
}
}
- public int getSystemGrammaticalGender(AttributionSource attributionSource, int userId) {
- String packageName = attributionSource.getPackageName();
- if (packageName == null) {
- Log.d(TAG, "Package name is null.");
- return GRAMMATICAL_GENDER_NOT_SPECIFIED;
- }
-
+ /**
+ * Returns the system global grammatical gender value for the requested user.
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
+ public int getSystemGrammaticalGender(int userId) {
synchronized (mLock) {
int grammaticalGender = mGrammaticalGenderCache.get(userId);
- return grammaticalGender < 0 ? GRAMMATICAL_GENDER_NOT_SPECIFIED : grammaticalGender;
+ return grammaticalGender < 0
+ ? Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED : grammaticalGender;
}
}
- private File getGrammaticalGenderFile(int userId) {
+ private static File getGrammaticalGenderFile(int userId) {
final File dir = new File(Environment.getDataSystemCeDirectory(userId),
TAG_GRAMMATICAL_INFLECTION);
return new File(dir, USER_SETTINGS_FILE_NAME);
}
- private byte[] toXmlByteArray(int grammaticalGender, FileOutputStream fileStream) {
-
- try {
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- TypedXmlSerializer out = Xml.resolveSerializer(fileStream);
- out.setOutput(outputStream, StandardCharsets.UTF_8.name());
- out.startDocument(/* encoding= */ null, /* standalone= */ true);
- out.startTag(null, TAG_GRAMMATICAL_INFLECTION);
- out.attributeInt(null, ATTR_NAME, grammaticalGender);
- out.endTag(null, TAG_GRAMMATICAL_INFLECTION);
- out.endDocument();
-
- return outputStream.toByteArray();
- } catch (IOException e) {
- return null;
- }
+ private static byte[] toXmlByteArray(int grammaticalGender, FileOutputStream fileStream)
+ throws IOException {
+ var outputStream = new ByteArrayOutputStream();
+ TypedXmlSerializer out = Xml.resolveSerializer(fileStream);
+ out.setOutput(outputStream, StandardCharsets.UTF_8.name());
+ out.startDocument(/* encoding= */ null, /* standalone= */ true);
+ out.startTag(null, TAG_GRAMMATICAL_INFLECTION);
+ out.attributeInt(null, ATTR_NAME, grammaticalGender);
+ out.endTag(null, TAG_GRAMMATICAL_INFLECTION);
+ out.endDocument();
+ return outputStream.toByteArray();
}
- private int getGrammaticalGenderFromXml(TypedXmlPullParser parser)
+ private static int getGrammaticalGenderFromXml(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
-
XmlUtils.nextElement(parser);
while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
String tagName = parser.getName();
@@ -359,20 +354,20 @@
}
}
- return GRAMMATICAL_GENDER_NOT_SPECIFIED;
+ return Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
}
- private void isCallerAllowed() {
+ private void enforceCallerPermissions() {
int callingUid = Binder.getCallingUid();
if (callingUid != Process.SYSTEM_UID && callingUid != Process.SHELL_UID
&& callingUid != Process.ROOT_UID) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_CONFIGURATION,
- "Caller must be system, shell, root or has CHANGE_CONFIGURATION permission.");
+ "Caller must be system, shell, root or hold CHANGE_CONFIGURATION permission.");
}
}
- private boolean checkSystemTermsOfAddressIsEnabled() {
+ private static boolean checkSystemTermsOfAddressIsEnabled() {
if (!systemTermsOfAddressEnabled()) {
Log.d(TAG, "The flag must be enabled to allow calling the API.");
return false;
@@ -387,25 +382,31 @@
@Override
public void onUserUnlocked(TargetUser user) {
+ if (!checkSystemTermsOfAddressIsEnabled()) {
+ return;
+ }
IoThread.getHandler().post(() -> {
- int userId = user.getUserIdentifier();
+ final int userId = user.getUserIdentifier();
final File file = getGrammaticalGenderFile(userId);
+ final int grammaticalGender;
synchronized (mLock) {
if (!file.exists()) {
Log.d(TAG, "User " + userId + " doesn't have the grammatical gender file.");
return;
}
- if (mGrammaticalGenderCache.indexOfKey(userId) < 0) {
- try (FileInputStream in = new FileInputStream(file)) {
- final TypedXmlPullParser parser = Xml.resolvePullParser(in);
- int grammaticalGender = getGrammaticalGenderFromXml(parser);
- mGrammaticalGenderCache.put(userId, grammaticalGender);
- updateConfiguration(grammaticalGender, userId);
- } catch (IOException | XmlPullParserException e) {
- Log.e(TAG, "Failed to parse XML configuration from " + file, e);
- }
+ if (mGrammaticalGenderCache.indexOfKey(userId) >= 0) {
+ return;
+ }
+ try (FileInputStream in = new FileInputStream(file)) {
+ final TypedXmlPullParser parser = Xml.resolvePullParser(in);
+ grammaticalGender = getGrammaticalGenderFromXml(parser);
+ mGrammaticalGenderCache.put(userId, grammaticalGender);
+ } catch (IOException | XmlPullParserException e) {
+ Log.e(TAG, "Failed to parse XML configuration from " + file, e);
+ return;
}
}
+ updateConfiguration(grammaticalGender, userId);
});
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 7d057a9..3503516 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -9492,6 +9492,12 @@
return false;
}
+ @Override
+ protected boolean setOverrideGender(Configuration requestsTmpConfig, int gender) {
+ return WindowProcessController.applyConfigGenderOverride(
+ requestsTmpConfig, gender, mAtmService.mGrammaticalManagerInternal, getUid());
+ }
+
@VisibleForTesting
@Override
Rect getAnimationBounds(int appRootTaskClipMode) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index fc05d17..f3e1dfb 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -949,7 +949,7 @@
}
configuration.setGrammaticalGender(
- mGrammaticalManagerInternal.retrieveSystemGrammaticalGender(configuration));
+ mGrammaticalManagerInternal.mergedFinalSystemGrammaticalGender());
synchronized (mGlobalLock) {
mForceResizableActivities = forceResizable;
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 31754bf..efd5202 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -534,8 +534,8 @@
nightMode);
boolean newLocalesSet = (locales != null) && setOverrideLocales(mRequestsTmpConfig,
locales);
- boolean newGenderSet = (gender != null) && setOverrideGender(mRequestsTmpConfig,
- gender);
+ boolean newGenderSet = setOverrideGender(mRequestsTmpConfig,
+ gender == null ? Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED : gender);
if (newNightModeSet || newLocalesSet || newGenderSet) {
onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
}
@@ -577,14 +577,11 @@
*
* @return true if the grammatical gender has been changed.
*/
- private boolean setOverrideGender(Configuration requestsTmpConfig,
+ protected boolean setOverrideGender(Configuration requestsTmpConfig,
@Configuration.GrammaticalGender int gender) {
- if (mRequestedOverrideConfiguration.getGrammaticalGender() == gender) {
- return false;
- } else {
- requestsTmpConfig.setGrammaticalGender(gender);
- return true;
- }
+ // Noop, only ActivityRecord and WindowProcessController have enough knowledge about the
+ // app to apply gender correctly.
+ return false;
}
public boolean isActivityTypeDream() {
diff --git a/services/core/java/com/android/server/wm/PackageConfigPersister.java b/services/core/java/com/android/server/wm/PackageConfigPersister.java
index 23127ac..9d597ea 100644
--- a/services/core/java/com/android/server/wm/PackageConfigPersister.java
+++ b/services/core/java/com/android/server/wm/PackageConfigPersister.java
@@ -169,6 +169,8 @@
LocaleOverlayHelper.combineLocalesIfOverlayExists(
modifiedRecord.mLocales, mAtm.getGlobalConfiguration().getLocales()),
modifiedRecord.mGrammaticalGender);
+ } else {
+ container.applyAppSpecificConfig(null, null, null);
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index fd1b5be..1c00fbb 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -84,6 +84,7 @@
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.Watchdog;
+import com.android.server.grammaticalinflection.GrammaticalInflectionManagerInternal;
import com.android.server.wm.ActivityTaskManagerService.HotPath;
import java.io.IOException;
@@ -324,8 +325,6 @@
*/
private volatile int mActivityStateFlags = ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER;
- private final boolean mCanUseSystemGrammaticalGender;
-
public WindowProcessController(@NonNull ActivityTaskManagerService atm,
@NonNull ApplicationInfo info, String name, int uid, int userId, Object owner,
@NonNull WindowProcessListener listener) {
@@ -349,9 +348,6 @@
mUseFifoUiScheduling = com.android.window.flags.Flags.fifoPriorityForMajorUiProcesses()
&& (isSysUiPackage || mAtm.isCallerRecents(uid));
- mCanUseSystemGrammaticalGender = mAtm.mGrammaticalManagerInternal != null
- && mAtm.mGrammaticalManagerInternal.canGetSystemGrammaticalGender(mUid,
- mInfo.packageName);
onConfigurationChanged(atm.getGlobalConfiguration());
mAtm.mPackageConfigPersister.updateConfigIfNeeded(this, mUserId, mInfo.packageName);
}
@@ -1612,11 +1608,6 @@
return;
}
- if (mCanUseSystemGrammaticalGender) {
- config.setGrammaticalGender(
- mAtm.mGrammaticalManagerInternal.getSystemGrammaticalGender(mUserId));
- }
-
if (mPauseConfigurationDispatchCount > 0) {
mHasPendingConfigurationChange = true;
return;
@@ -2139,4 +2130,34 @@
void dumpDebug(ProtoOutputStream proto, long fieldId) {
mListener.dumpDebug(proto, fieldId);
}
+
+ @Override
+ protected boolean setOverrideGender(Configuration requestsTmpConfig, int gender) {
+ return applyConfigGenderOverride(requestsTmpConfig, gender,
+ mAtm.mGrammaticalManagerInternal, mUid);
+ }
+
+ static boolean applyConfigGenderOverride(@NonNull Configuration overrideConfig,
+ @Configuration.GrammaticalGender int override,
+ GrammaticalInflectionManagerInternal service, int uid) {
+ final boolean canGetSystemValue = service != null
+ && service.canGetSystemGrammaticalGender(uid);
+
+ // The priority here is as follows:
+ // - app-specific override if set
+ // - system value if allowed to see it
+ // - global configuration otherwise
+ final int targetValue = (override != Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED)
+ ? override
+ : canGetSystemValue
+ ? Configuration.GRAMMATICAL_GENDER_UNDEFINED
+ : service != null
+ ? service.getGrammaticalGenderFromDeveloperSettings()
+ : Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
+ if (overrideConfig.getGrammaticalGenderRaw() == targetValue) {
+ return false;
+ }
+ overrideConfig.setGrammaticalGender(targetValue);
+ return true;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/grammaticalinflection/GrammaticalInflectionBackupTest.java b/services/tests/servicestests/src/com/android/server/grammaticalinflection/GrammaticalInflectionBackupTest.java
index af6f6f2..608b306 100644
--- a/services/tests/servicestests/src/com/android/server/grammaticalinflection/GrammaticalInflectionBackupTest.java
+++ b/services/tests/servicestests/src/com/android/server/grammaticalinflection/GrammaticalInflectionBackupTest.java
@@ -112,7 +112,7 @@
public void testSystemBackupPayload_returnsGender()
throws IOException, ClassNotFoundException {
doReturn(Configuration.GRAMMATICAL_GENDER_MASCULINE).when(mGrammaticalInflectionService)
- .getSystemGrammaticalGender(any(), eq(DEFAULT_USER_ID));
+ .getSystemGrammaticalGender(eq(DEFAULT_USER_ID));
int gender = convertByteArrayToInt(mBackupHelper.getSystemBackupPayload(DEFAULT_USER_ID));
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 1da5001..b0a3374 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -525,10 +525,13 @@
// The activity shouldn't start relaunching since it doesn't have any desk resources.
assertFalse(activity.isRelaunching());
+ // The activity configuration ui mode should match.
+ final var activityConfig = activity.getConfiguration();
+ assertEquals(newConfig.uiMode, activityConfig.uiMode);
// The configuration change is still sent to the activity, even if it doesn't relaunch.
final ActivityConfigurationChangeItem expected =
- ActivityConfigurationChangeItem.obtain(activity.token, newConfig,
+ ActivityConfigurationChangeItem.obtain(activity.token, activityConfig,
activity.getActivityWindowInfo());
verify(mClientLifecycleManager).scheduleTransactionItem(
eq(activity.app.getThread()), eq(expected));
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 87f26e5..c45c86c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -56,6 +56,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.res.Configuration;
import android.database.ContentObserver;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.display.DisplayManagerGlobal;
@@ -86,6 +87,7 @@
import com.android.server.display.DisplayControl;
import com.android.server.display.color.ColorDisplayService;
import com.android.server.firewall.IntentFirewall;
+import com.android.server.grammaticalinflection.GrammaticalInflectionManagerInternal;
import com.android.server.input.InputManagerService;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.UserManagerService;
@@ -208,6 +210,11 @@
setUpLocalServices();
setUpActivityTaskManagerService();
setUpWindowManagerService();
+
+ // We never load the system settings in the tests, thus need to setup the grammatical
+ // gender configuration explicitly.
+ mAtmService.getGlobalConfiguration().setGrammaticalGender(
+ Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED);
}
private void setUpSystemCore() {
@@ -337,6 +344,18 @@
};
when(umi.isUserVisible(anyInt())).thenAnswer(isUserVisibleAnswer);
when(umi.isUserVisible(anyInt(), anyInt())).thenAnswer(isUserVisibleAnswer);
+
+ final var gimi = mock(
+ GrammaticalInflectionManagerInternal.class, withSettings().stubOnly());
+ doReturn(Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED).when(
+ gimi).getGrammaticalGenderFromDeveloperSettings();
+ doReturn(Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED).when(
+ gimi).getSystemGrammaticalGender(anyInt());
+ doReturn(Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED).when(
+ gimi).mergedFinalSystemGrammaticalGender();
+ doReturn(false).when(gimi).canGetSystemGrammaticalGender(anyInt());
+ doReturn(gimi).when(
+ () -> LocalServices.getService(GrammaticalInflectionManagerInternal.class));
}
private void setUpActivityTaskManagerService() {
@@ -475,6 +494,7 @@
LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
LocalServices.removeServiceForTest(UserManagerInternal.class);
LocalServices.removeServiceForTest(ImeTargetVisibilityPolicy.class);
+ LocalServices.removeServiceForTest(GrammaticalInflectionManagerInternal.class);
}
Description getDescription() {