diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index d4644c59fa529..a4a39e9618900 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1027,6 +1027,9 @@ + + diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index ec486437734b5..dec403cf5c463 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -29,6 +29,7 @@ import android.content.IIntentSender; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.res.CompatibilityInfo; +import android.content.res.Configuration; import android.os.Bundle; import android.os.IBinder; import android.os.LocaleList; @@ -622,10 +623,19 @@ public abstract class ActivityTaskManagerInternal { @Nullable public final LocaleList mLocales; + /** + * Gender for the application, null if app-specific grammatical gender is not set. + */ + @Nullable + public final @Configuration.GrammaticalGender + Integer mGrammaticalGender; + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public PackageConfig(Integer nightMode, LocaleList locales) { + public PackageConfig(Integer nightMode, LocaleList locales, + @Configuration.GrammaticalGender Integer grammaticalGender) { mNightMode = nightMode; mLocales = locales; + mGrammaticalGender = grammaticalGender; } /** @@ -659,6 +669,13 @@ public abstract class ActivityTaskManagerInternal { */ PackageConfigurationUpdater setLocales(LocaleList locales); + /** + * Sets the gender for the current application. This setting is persisted and will + * override the system configuration for this application. + */ + PackageConfigurationUpdater setGrammaticalGender( + @Configuration.GrammaticalGender int gender); + /** * Commit changes. * @return true if the configuration changes were persisted, diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java index 0c6cea82e00cd..58d4e82961f68 100644 --- a/services/core/java/com/android/server/wm/ConfigurationContainer.java +++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java @@ -536,16 +536,19 @@ public abstract class ConfigurationContainer { * 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) { + public boolean applyAppSpecificConfig(Integer nightMode, LocaleList locales, + @Configuration.GrammaticalGender Integer gender) { mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration()); boolean newNightModeSet = (nightMode != null) && setOverrideNightMode(mRequestsTmpConfig, nightMode); boolean newLocalesSet = (locales != null) && setOverrideLocales(mRequestsTmpConfig, locales); - if (newNightModeSet || newLocalesSet) { + boolean newGenderSet = (gender != null) && setOverrideGender(mRequestsTmpConfig, + gender); + if (newNightModeSet || newLocalesSet || newGenderSet) { onRequestedOverrideConfigurationChanged(mRequestsTmpConfig); } - return newNightModeSet || newLocalesSet; + return newNightModeSet || newLocalesSet || newGenderSet; } /** @@ -578,6 +581,21 @@ public abstract class ConfigurationContainer { return true; } + /** + * Overrides the gender to this ConfigurationContainer. + * + * @return true if the grammatical gender has been changed. + */ + private boolean setOverrideGender(Configuration requestsTmpConfig, + @Configuration.GrammaticalGender int gender) { + if (mRequestedOverrideConfiguration.getGrammaticalGender() == gender) { + return false; + } else { + requestsTmpConfig.setGrammaticalGender(gender); + return true; + } + } + public boolean isActivityTypeDream() { return getActivityType() == ACTIVITY_TYPE_DREAM; } diff --git a/services/core/java/com/android/server/wm/PackageConfigPersister.java b/services/core/java/com/android/server/wm/PackageConfigPersister.java index 18a7d2e760fc9..23127ac1ba098 100644 --- a/services/core/java/com/android/server/wm/PackageConfigPersister.java +++ b/services/core/java/com/android/server/wm/PackageConfigPersister.java @@ -16,6 +16,8 @@ package com.android.server.wm; +import static android.content.res.Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED; + import android.annotation.NonNull; import android.content.res.Configuration; import android.os.Environment; @@ -165,7 +167,8 @@ public class PackageConfigPersister { if (modifiedRecord != null) { container.applyAppSpecificConfig(modifiedRecord.mNightMode, LocaleOverlayHelper.combineLocalesIfOverlayExists( - modifiedRecord.mLocales, mAtm.getGlobalConfiguration().getLocales())); + modifiedRecord.mLocales, mAtm.getGlobalConfiguration().getLocales()), + modifiedRecord.mGrammaticalGender); } } } @@ -188,16 +191,19 @@ public class PackageConfigPersister { } boolean isNightModeChanged = updateNightMode(impl.getNightMode(), record); boolean isLocalesChanged = updateLocales(impl.getLocales(), record); + boolean isGenderChanged = updateGender(impl.getGrammaticalGender(), record); if ((record.mNightMode == null || record.isResetNightMode()) - && (record.mLocales == null || record.mLocales.isEmpty())) { + && (record.mLocales == null || record.mLocales.isEmpty()) + && (record.mGrammaticalGender == null + || record.mGrammaticalGender == GRAMMATICAL_GENDER_NOT_SPECIFIED)) { // if all values default to system settings, we can remove the package. removePackage(packageName, userId); // if there was a pre-existing record for the package that was deleted, // we return true (since it was successfully deleted), else false (since there was // no change to the previous state). return isRecordPresent; - } else if (!isNightModeChanged && !isLocalesChanged) { + } else if (!isNightModeChanged && !isLocalesChanged && !isGenderChanged) { return false; } else { final PackageConfigRecord pendingRecord = @@ -211,7 +217,8 @@ public class PackageConfigPersister { } if (!updateNightMode(record.mNightMode, writeRecord) - && !updateLocales(record.mLocales, writeRecord)) { + && !updateLocales(record.mLocales, writeRecord) + && !updateGender(record.mGrammaticalGender, writeRecord)) { return false; } @@ -240,6 +247,15 @@ public class PackageConfigPersister { return true; } + private boolean updateGender(@Configuration.GrammaticalGender Integer requestedGender, + PackageConfigRecord record) { + if (requestedGender == null || requestedGender.equals(record.mGrammaticalGender)) { + return false; + } + record.mGrammaticalGender = requestedGender; + return true; + } + @GuardedBy("mLock") void removeUser(int userId) { synchronized (mLock) { @@ -305,7 +321,9 @@ public class PackageConfigPersister { return null; } return new ActivityTaskManagerInternal.PackageConfig( - packageConfigRecord.mNightMode, packageConfigRecord.mLocales); + packageConfigRecord.mNightMode, + packageConfigRecord.mLocales, + packageConfigRecord.mGrammaticalGender); } } @@ -336,6 +354,8 @@ public class PackageConfigPersister { final int mUserId; Integer mNightMode; LocaleList mLocales; + @Configuration.GrammaticalGender + Integer mGrammaticalGender; PackageConfigRecord(String name, int userId) { mName = name; diff --git a/services/core/java/com/android/server/wm/PackageConfigurationUpdaterImpl.java b/services/core/java/com/android/server/wm/PackageConfigurationUpdaterImpl.java index f3be66c5e6da3..2cf8a4a7c1464 100644 --- a/services/core/java/com/android/server/wm/PackageConfigurationUpdaterImpl.java +++ b/services/core/java/com/android/server/wm/PackageConfigurationUpdaterImpl.java @@ -17,6 +17,7 @@ package com.android.server.wm; import android.content.pm.PackageManager; +import android.content.res.Configuration; import android.os.Binder; import android.os.LocaleList; import android.util.ArraySet; @@ -33,6 +34,8 @@ final class PackageConfigurationUpdaterImpl implements private final Optional mPid; private Integer mNightMode; private LocaleList mLocales; + private @Configuration.GrammaticalGender + int mGrammaticalGender; private String mPackageName; private int mUserId; private ActivityTaskManagerService mAtm; @@ -67,6 +70,15 @@ final class PackageConfigurationUpdaterImpl implements return this; } + @Override + public ActivityTaskManagerInternal.PackageConfigurationUpdater setGrammaticalGender( + @Configuration.GrammaticalGender int gender) { + synchronized (this) { + mGrammaticalGender = gender; + } + return this; + } + @Override public boolean commit() { synchronized (this) { @@ -112,12 +124,12 @@ final class PackageConfigurationUpdaterImpl implements for (int i = processes.size() - 1; i >= 0; i--) { final WindowProcessController wpc = processes.valueAt(i); if (wpc.mInfo.packageName.equals(packageName)) { - wpc.applyAppSpecificConfig(mNightMode, localesOverride); + wpc.applyAppSpecificConfig(mNightMode, localesOverride, mGrammaticalGender); } // Always inform individual activities about the update, since activities from other // packages may be sharing this process wpc.updateAppSpecificSettingsForAllActivitiesInPackage(packageName, mNightMode, - localesOverride); + localesOverride, mGrammaticalGender); } } @@ -128,4 +140,9 @@ final class PackageConfigurationUpdaterImpl implements LocaleList getLocales() { return mLocales; } + + @Configuration.GrammaticalGender + Integer getGrammaticalGender() { + return mGrammaticalGender; + } } diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index e9b81ec030817..f9670ccbed0a0 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -867,13 +867,13 @@ public class WindowProcessController extends ConfigurationContainer= 0; --i) { final ActivityRecord r = mActivities.get(i); // Activities from other packages could be sharing this process. Only propagate updates // to those activities that are part of the package whose app-specific settings changed if (packageName.equals(r.packageName) - && r.applyAppSpecificConfig(nightMode, localesOverride) + && r.applyAppSpecificConfig(nightMode, localesOverride, gender) && r.isVisibleRequested()) { r.ensureActivityConfiguration(0 /* globalChanges */, true /* preserveWindow */); }