Merge changes from topic "configuration_gender"
* changes: Fix test case fail Add a new field in Configuration and persist the field Add a system service for grammatical gender
This commit is contained in:
@@ -5650,6 +5650,11 @@ package android.app {
|
||||
field public static final int MODE_UNKNOWN = 0; // 0x0
|
||||
}
|
||||
|
||||
public class GrammaticalInflectionManager {
|
||||
method public int getApplicationGrammaticalGender();
|
||||
method public void setRequestedApplicationGrammaticalGender(int);
|
||||
}
|
||||
|
||||
public class Instrumentation {
|
||||
ctor public Instrumentation();
|
||||
method public android.os.TestLooperManager acquireLooperManager(android.os.Looper);
|
||||
@@ -10005,6 +10010,7 @@ package android.content {
|
||||
field public static final String FILE_INTEGRITY_SERVICE = "file_integrity";
|
||||
field public static final String FINGERPRINT_SERVICE = "fingerprint";
|
||||
field public static final String GAME_SERVICE = "game";
|
||||
field public static final String GRAMMATICAL_INFLECTION_SERVICE = "grammatical_inflection";
|
||||
field public static final String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
|
||||
field public static final String HEALTHCONNECT_SERVICE = "healthconnect";
|
||||
field public static final String INPUT_METHOD_SERVICE = "input_method";
|
||||
@@ -11261,6 +11267,7 @@ package android.content.pm {
|
||||
field public static final int CONFIG_DENSITY = 4096; // 0x1000
|
||||
field public static final int CONFIG_FONT_SCALE = 1073741824; // 0x40000000
|
||||
field public static final int CONFIG_FONT_WEIGHT_ADJUSTMENT = 268435456; // 0x10000000
|
||||
field public static final int CONFIG_GRAMMATICAL_GENDER = 32768; // 0x8000
|
||||
field public static final int CONFIG_KEYBOARD = 16; // 0x10
|
||||
field public static final int CONFIG_KEYBOARD_HIDDEN = 32; // 0x20
|
||||
field public static final int CONFIG_LAYOUT_DIRECTION = 8192; // 0x2000
|
||||
@@ -12875,6 +12882,7 @@ package android.content.res {
|
||||
method public int diff(android.content.res.Configuration);
|
||||
method public boolean equals(android.content.res.Configuration);
|
||||
method @NonNull public static android.content.res.Configuration generateDelta(@NonNull android.content.res.Configuration, @NonNull android.content.res.Configuration);
|
||||
method public int getGrammaticalGender();
|
||||
method public int getLayoutDirection();
|
||||
method @NonNull public android.os.LocaleList getLocales();
|
||||
method public boolean isLayoutSizeAtLeast(int);
|
||||
@@ -12904,6 +12912,10 @@ package android.content.res {
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.content.res.Configuration> CREATOR;
|
||||
field public static final int DENSITY_DPI_UNDEFINED = 0; // 0x0
|
||||
field public static final int FONT_WEIGHT_ADJUSTMENT_UNDEFINED = 2147483647; // 0x7fffffff
|
||||
field public static final int GRAMMATICAL_GENDER_FEMININE = 3; // 0x3
|
||||
field public static final int GRAMMATICAL_GENDER_MASCULINE = 4; // 0x4
|
||||
field public static final int GRAMMATICAL_GENDER_NEUTRAL = 2; // 0x2
|
||||
field public static final int GRAMMATICAL_GENDER_NOT_SPECIFIED = 0; // 0x0
|
||||
field public static final int HARDKEYBOARDHIDDEN_NO = 1; // 0x1
|
||||
field public static final int HARDKEYBOARDHIDDEN_UNDEFINED = 0; // 0x0
|
||||
field public static final int HARDKEYBOARDHIDDEN_YES = 2; // 0x2
|
||||
|
||||
93
core/java/android/app/GrammaticalInflectionManager.java
Normal file
93
core/java/android/app/GrammaticalInflectionManager.java
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 android.app;
|
||||
|
||||
import android.annotation.SystemService;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* This class allow applications to control granular grammatical inflection settings (such as
|
||||
* per-app grammatical gender).
|
||||
*/
|
||||
@SystemService(Context.GRAMMATICAL_INFLECTION_SERVICE)
|
||||
public class GrammaticalInflectionManager {
|
||||
private static final Set<Integer> VALID_GENDER_VALUES = new HashSet<>(Arrays.asList(
|
||||
Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED,
|
||||
Configuration.GRAMMATICAL_GENDER_NEUTRAL,
|
||||
Configuration.GRAMMATICAL_GENDER_FEMININE,
|
||||
Configuration.GRAMMATICAL_GENDER_MASCULINE));
|
||||
|
||||
private final Context mContext;
|
||||
private final IGrammaticalInflectionManager mService;
|
||||
|
||||
/** @hide Instantiated by ContextImpl */
|
||||
public GrammaticalInflectionManager(Context context, IGrammaticalInflectionManager service) {
|
||||
mContext = context;
|
||||
mService = service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current grammatical gender for the calling app. A new value can be requested via
|
||||
* {@link #setRequestedApplicationGrammaticalGender(int)} and will be updated with a new
|
||||
* configuration change. The method always returns the value received with the last received
|
||||
* configuration change.
|
||||
*
|
||||
* @return the value of grammatical gender
|
||||
* @see Configuration#getGrammaticalGender
|
||||
*/
|
||||
@Configuration.GrammaticalGender
|
||||
public int getApplicationGrammaticalGender() {
|
||||
return mContext.getApplicationContext()
|
||||
.getResources()
|
||||
.getConfiguration()
|
||||
.getGrammaticalGender();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current grammatical gender for the calling app (keyed by package name and user ID
|
||||
* retrieved from the calling pid).
|
||||
*
|
||||
* <p><b>Note:</b> Changes to app grammatical gender will result in a configuration change (and
|
||||
* potentially an Activity re-creation) being applied to the specified application. For more
|
||||
* information, see the <a
|
||||
* href="https://developer.android.com/guide/topics/resources/runtime-changes">section on
|
||||
* handling configuration changes</a>. The set grammatical gender are persisted across
|
||||
* application restarts; they are backed up if the user has enabled Backup & Restore.`
|
||||
*
|
||||
* @param grammaticalGender the terms of address the user preferred in an application.
|
||||
* @see Configuration#getGrammaticalGender
|
||||
*/
|
||||
public void setRequestedApplicationGrammaticalGender(
|
||||
@Configuration.GrammaticalGender int grammaticalGender) {
|
||||
if (!VALID_GENDER_VALUES.contains(grammaticalGender)) {
|
||||
throw new IllegalArgumentException("Unknown grammatical gender");
|
||||
}
|
||||
|
||||
try {
|
||||
mService.setRequestedApplicationGrammaticalGender(
|
||||
mContext.getPackageName(), mContext.getUserId(), grammaticalGender);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
19
core/java/android/app/IGrammaticalInflectionManager.aidl
Normal file
19
core/java/android/app/IGrammaticalInflectionManager.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
package android.app;
|
||||
|
||||
|
||||
/**
|
||||
* Internal interface used to control app-specific gender.
|
||||
*
|
||||
* <p>Use the {@link android.app.GrammarInflectionManager} class rather than going through
|
||||
* this Binder interface directly. See {@link android.app.GrammarInflectionManager} for
|
||||
* more complete documentation.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
interface IGrammaticalInflectionManager {
|
||||
|
||||
/**
|
||||
* Sets a specified app’s app-specific grammatical gender.
|
||||
*/
|
||||
void setRequestedApplicationGrammaticalGender(String appPackageName, int userId, int gender);
|
||||
}
|
||||
@@ -1547,6 +1547,7 @@ public final class SystemServiceRegistry {
|
||||
IAmbientContextManager.Stub.asInterface(iBinder);
|
||||
return new AmbientContextManager(ctx.getOuterContext(), manager);
|
||||
}});
|
||||
|
||||
registerService(Context.WEARABLE_SENSING_SERVICE, WearableSensingManager.class,
|
||||
new CachedServiceFetcher<WearableSensingManager>() {
|
||||
@Override
|
||||
@@ -1559,6 +1560,18 @@ public final class SystemServiceRegistry {
|
||||
return new WearableSensingManager(ctx.getOuterContext(), manager);
|
||||
}});
|
||||
|
||||
registerService(Context.GRAMMATICAL_INFLECTION_SERVICE, GrammaticalInflectionManager.class,
|
||||
new CachedServiceFetcher<GrammaticalInflectionManager>() {
|
||||
@Override
|
||||
public GrammaticalInflectionManager createService(ContextImpl ctx)
|
||||
throws ServiceNotFoundException {
|
||||
return new GrammaticalInflectionManager(ctx,
|
||||
IGrammaticalInflectionManager.Stub.asInterface(
|
||||
ServiceManager.getServiceOrThrow(
|
||||
Context.GRAMMATICAL_INFLECTION_SERVICE)));
|
||||
}});
|
||||
|
||||
|
||||
sInitializing = true;
|
||||
try {
|
||||
// Note: the following functions need to be @SystemApis, once they become mainline
|
||||
|
||||
@@ -40,6 +40,7 @@ import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.BroadcastOptions;
|
||||
import android.app.GameManager;
|
||||
import android.app.GrammaticalInflectionManager;
|
||||
import android.app.IApplicationThread;
|
||||
import android.app.IServiceConnection;
|
||||
import android.app.VrManager;
|
||||
@@ -3973,6 +3974,8 @@ public abstract class Context {
|
||||
CREDENTIAL_SERVICE,
|
||||
DEVICE_LOCK_SERVICE,
|
||||
VIRTUALIZATION_SERVICE,
|
||||
GRAMMATICAL_INFLECTION_SERVICE,
|
||||
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface ServiceName {}
|
||||
@@ -6168,6 +6171,14 @@ public abstract class Context {
|
||||
@SystemApi
|
||||
public static final String VIRTUALIZATION_SERVICE = "virtualization";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService(String)} to retrieve a
|
||||
* {@link GrammaticalInflectionManager}.
|
||||
*
|
||||
* @see #getSystemService(String)
|
||||
*/
|
||||
public static final String GRAMMATICAL_INFLECTION_SERVICE = "grammatical_inflection";
|
||||
|
||||
/**
|
||||
* Determine whether the given permission is allowed for a particular
|
||||
* process and user ID running in the system.
|
||||
|
||||
@@ -807,6 +807,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
|
||||
CONFIG_LAYOUT_DIRECTION,
|
||||
CONFIG_COLOR_MODE,
|
||||
CONFIG_FONT_SCALE,
|
||||
CONFIG_GRAMMATICAL_GENDER,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Config {}
|
||||
@@ -915,6 +916,12 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
|
||||
* range. Set from the {@link android.R.attr#configChanges} attribute.
|
||||
*/
|
||||
public static final int CONFIG_COLOR_MODE = 0x4000;
|
||||
/**
|
||||
* Bit in {@link #configChanges} that indicates that the activity
|
||||
* can itself handle the change to gender. Set from the
|
||||
* {@link android.R.attr#configChanges} attribute.
|
||||
*/
|
||||
public static final int CONFIG_GRAMMATICAL_GENDER = 0x8000;
|
||||
/**
|
||||
* Bit in {@link #configChanges} that indicates that the activity
|
||||
* can itself handle asset path changes. Set from the {@link android.R.attr#configChanges}
|
||||
@@ -946,7 +953,6 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
|
||||
* not a core resource configuration, but a higher-level value, so its
|
||||
* constant starts at the high bits.
|
||||
*/
|
||||
|
||||
public static final int CONFIG_FONT_WEIGHT_ADJUSTMENT = 0x10000000;
|
||||
|
||||
/** @hide
|
||||
|
||||
@@ -46,6 +46,7 @@ import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.TestApi;
|
||||
import android.app.GrammaticalInflectionManager;
|
||||
import android.app.WindowConfiguration;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.LocaleProto;
|
||||
@@ -141,6 +142,44 @@ public final class Configuration implements Parcelable, Comparable<Configuration
|
||||
@UnsupportedAppUsage
|
||||
public boolean userSetLocale;
|
||||
|
||||
/**
|
||||
* Current user preference for the grammatical gender.
|
||||
*/
|
||||
@GrammaticalGender
|
||||
private int mGrammaticalGender;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(prefix = { "GRAMMATICAL_GENDER_" }, value = {
|
||||
GRAMMATICAL_GENDER_NOT_SPECIFIED,
|
||||
GRAMMATICAL_GENDER_NEUTRAL,
|
||||
GRAMMATICAL_GENDER_FEMININE,
|
||||
GRAMMATICAL_GENDER_MASCULINE,
|
||||
})
|
||||
public @interface GrammaticalGender {}
|
||||
|
||||
/**
|
||||
* Constant for grammatical gender: to indicate the user has not specified the terms
|
||||
* of address for the application.
|
||||
*/
|
||||
public static final int GRAMMATICAL_GENDER_NOT_SPECIFIED = 0;
|
||||
|
||||
/**
|
||||
* Constant for grammatical gender: to indicate the terms of address the user
|
||||
* preferred in an application is neuter.
|
||||
*/
|
||||
public static final int GRAMMATICAL_GENDER_NEUTRAL = 2;
|
||||
|
||||
/**
|
||||
* Constant for grammatical gender: to indicate the terms of address the user
|
||||
* preferred in an application is feminine.
|
||||
*/
|
||||
public static final int GRAMMATICAL_GENDER_FEMININE = 3;
|
||||
|
||||
/**
|
||||
* Constant for grammatical gender: to indicate the terms of address the user
|
||||
* preferred in an application is masculine.
|
||||
*/
|
||||
public static final int GRAMMATICAL_GENDER_MASCULINE = 4;
|
||||
|
||||
/** Constant for {@link #colorMode}: bits that encode whether the screen is wide gamut. */
|
||||
public static final int COLOR_MODE_WIDE_COLOR_GAMUT_MASK = 0x3;
|
||||
@@ -1024,6 +1063,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
|
||||
}
|
||||
o.fixUpLocaleList();
|
||||
mLocaleList = o.mLocaleList;
|
||||
mGrammaticalGender = o.mGrammaticalGender;
|
||||
userSetLocale = o.userSetLocale;
|
||||
touchscreen = o.touchscreen;
|
||||
keyboard = o.keyboard;
|
||||
@@ -1510,6 +1550,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
|
||||
seq = 0;
|
||||
windowConfiguration.setToDefaults();
|
||||
fontWeightAdjustment = FONT_WEIGHT_ADJUSTMENT_UNDEFINED;
|
||||
mGrammaticalGender = GRAMMATICAL_GENDER_NOT_SPECIFIED;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1712,6 +1753,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration
|
||||
changed |= ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT;
|
||||
fontWeightAdjustment = delta.fontWeightAdjustment;
|
||||
}
|
||||
if (delta.mGrammaticalGender != mGrammaticalGender) {
|
||||
changed |= ActivityInfo.CONFIG_GRAMMATICAL_GENDER;
|
||||
mGrammaticalGender = delta.mGrammaticalGender;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
@@ -1929,6 +1974,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration
|
||||
&& fontWeightAdjustment != delta.fontWeightAdjustment) {
|
||||
changed |= ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT;
|
||||
}
|
||||
|
||||
if (!publicOnly&& mGrammaticalGender != delta.mGrammaticalGender) {
|
||||
changed |= ActivityInfo.CONFIG_GRAMMATICAL_GENDER;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
@@ -2023,6 +2072,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
|
||||
dest.writeInt(assetsSeq);
|
||||
dest.writeInt(seq);
|
||||
dest.writeInt(fontWeightAdjustment);
|
||||
dest.writeInt(mGrammaticalGender);
|
||||
}
|
||||
|
||||
public void readFromParcel(Parcel source) {
|
||||
@@ -2055,6 +2105,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
|
||||
assetsSeq = source.readInt();
|
||||
seq = source.readInt();
|
||||
fontWeightAdjustment = source.readInt();
|
||||
mGrammaticalGender = source.readInt();
|
||||
}
|
||||
|
||||
public static final @android.annotation.NonNull Parcelable.Creator<Configuration> CREATOR
|
||||
@@ -2155,6 +2206,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
|
||||
if (n != 0) return n;
|
||||
n = this.fontWeightAdjustment - that.fontWeightAdjustment;
|
||||
if (n != 0) return n;
|
||||
n = this.mGrammaticalGender - that.mGrammaticalGender;
|
||||
if (n != 0) return n;
|
||||
|
||||
// if (n != 0) return n;
|
||||
return n;
|
||||
@@ -2196,9 +2249,36 @@ public final class Configuration implements Parcelable, Comparable<Configuration
|
||||
result = 31 * result + densityDpi;
|
||||
result = 31 * result + assetsSeq;
|
||||
result = 31 * result + fontWeightAdjustment;
|
||||
result = 31 * result + mGrammaticalGender;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user preference for the grammatical gender. Will be
|
||||
* {@link #GRAMMATICAL_GENDER_NOT_SPECIFIED} or
|
||||
* {@link #GRAMMATICAL_GENDER_NEUTRAL} or
|
||||
* {@link #GRAMMATICAL_GENDER_FEMININE} or
|
||||
* {@link #GRAMMATICAL_GENDER_MASCULINE}.
|
||||
*
|
||||
* @return The preferred grammatical gender.
|
||||
*/
|
||||
@GrammaticalGender
|
||||
public int getGrammaticalGender() {
|
||||
return mGrammaticalGender;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the user preference for the grammatical gender. This is only for frameworks to easily
|
||||
* override the gender in the configuration. To update the grammatical gender for an application
|
||||
* use {@link GrammaticalInflectionManager#setRequestedApplicationGrammaticalGender(int)}.
|
||||
*
|
||||
* @param grammaticalGender The preferred grammatical gender.
|
||||
* @hide
|
||||
*/
|
||||
public void setGrammaticalGender(@GrammaticalGender int grammaticalGender) {
|
||||
mGrammaticalGender = grammaticalGender;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the locale list. This is the preferred way for getting the locales (instead of using
|
||||
* the direct accessor to {@link #locale}, which would only provide the primary locale).
|
||||
|
||||
@@ -1027,6 +1027,9 @@
|
||||
<flag name="layoutDirection" value="0x2000" />
|
||||
<!-- The color mode of the screen has changed (color gamut or dynamic range). -->
|
||||
<flag name="colorMode" value="0x4000" />
|
||||
<!-- The grammatical gender has changed, for example the user set the grammatical gender
|
||||
from the UI. -->
|
||||
<flag name="grammaticalGender" value="0x8000" />
|
||||
<!-- The font scaling factor has changed, that is the user has
|
||||
selected a new global font size. -->
|
||||
<flag name="fontScale" value="0x40000000" />
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.grammaticalinflection;
|
||||
|
||||
import static android.content.res.Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
|
||||
|
||||
import android.app.IGrammaticalInflectionManager;
|
||||
import android.content.Context;
|
||||
import android.os.IBinder;
|
||||
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.SystemService;
|
||||
import com.android.server.wm.ActivityTaskManagerInternal;
|
||||
|
||||
/**
|
||||
* The implementation of IGrammaticalInflectionManager.aidl.
|
||||
*
|
||||
* <p>This service is API entry point for storing app-specific grammatical inflection.
|
||||
*/
|
||||
public class GrammaticalInflectionService extends SystemService {
|
||||
|
||||
private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
|
||||
|
||||
/**
|
||||
* Initializes the system service.
|
||||
* <p>
|
||||
* Subclasses must define a single argument constructor that accepts the context
|
||||
* and passes it to super.
|
||||
* </p>
|
||||
*
|
||||
* @param context The system server context.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public GrammaticalInflectionService(Context context) {
|
||||
super(context);
|
||||
mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
publishBinderService(Context.GRAMMATICAL_INFLECTION_SERVICE, mService);
|
||||
}
|
||||
|
||||
private final IBinder mService = new IGrammaticalInflectionManager.Stub() {
|
||||
@Override
|
||||
public void setRequestedApplicationGrammaticalGender(
|
||||
String appPackageName, int userId, int gender) {
|
||||
GrammaticalInflectionService.this.setRequestedApplicationGrammaticalGender(
|
||||
appPackageName, userId, gender);
|
||||
}
|
||||
};
|
||||
|
||||
private void setRequestedApplicationGrammaticalGender(
|
||||
String appPackageName, int userId, int gender) {
|
||||
final ActivityTaskManagerInternal.PackageConfigurationUpdater updater =
|
||||
mActivityTaskManagerInternal.createPackageConfigurationUpdater(appPackageName,
|
||||
userId);
|
||||
|
||||
updater.setGrammaticalGender(gender).commit();
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -536,16 +536,19 @@ public abstract class ConfigurationContainer<E extends 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<E extends 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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<Integer> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -868,13 +868,13 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
|
||||
// TODO(b/199277729): Consider whether we need to add special casing for edge cases like
|
||||
// activity-embeddings etc.
|
||||
void updateAppSpecificSettingsForAllActivitiesInPackage(String packageName, Integer nightMode,
|
||||
LocaleList localesOverride) {
|
||||
LocaleList localesOverride, @Configuration.GrammaticalGender int gender) {
|
||||
for (int i = mActivities.size() - 1; i >= 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 */);
|
||||
}
|
||||
|
||||
@@ -132,6 +132,7 @@ import com.android.server.display.DisplayManagerService;
|
||||
import com.android.server.display.color.ColorDisplayService;
|
||||
import com.android.server.dreams.DreamManagerService;
|
||||
import com.android.server.emergency.EmergencyAffordanceService;
|
||||
import com.android.server.grammaticalinflection.GrammaticalInflectionService;
|
||||
import com.android.server.gpu.GpuService;
|
||||
import com.android.server.graphics.fonts.FontManagerService;
|
||||
import com.android.server.hdmi.HdmiControlService;
|
||||
@@ -1769,6 +1770,14 @@ public final class SystemServer implements Dumpable {
|
||||
}
|
||||
t.traceEnd();
|
||||
|
||||
t.traceBegin("StartGrammarInflectionService");
|
||||
try {
|
||||
mSystemServiceManager.startService(GrammaticalInflectionService.class);
|
||||
} catch (Throwable e) {
|
||||
reportWtf("starting GrammarInflectionService service", e);
|
||||
}
|
||||
t.traceEnd();
|
||||
|
||||
t.traceBegin("UpdatePackagesIfNeeded");
|
||||
try {
|
||||
Watchdog.getInstance().pauseWatchingCurrentThread("dexopt");
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server.locales;
|
||||
|
||||
import static android.content.res.Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.os.LocaleList;
|
||||
|
||||
@@ -29,6 +31,8 @@ class FakePackageConfigurationUpdater implements PackageConfigurationUpdater {
|
||||
|
||||
FakePackageConfigurationUpdater() {}
|
||||
|
||||
private int mGender = GRAMMATICAL_GENDER_NOT_SPECIFIED;
|
||||
|
||||
LocaleList mLocales = null;
|
||||
|
||||
@Override
|
||||
@@ -42,6 +46,12 @@ class FakePackageConfigurationUpdater implements PackageConfigurationUpdater {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PackageConfigurationUpdater setGrammaticalGender(int gender) {
|
||||
mGender = gender;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean commit() {
|
||||
return mLocales != null;
|
||||
@@ -56,4 +66,10 @@ class FakePackageConfigurationUpdater implements PackageConfigurationUpdater {
|
||||
return mLocales;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the gender that were stored during the test run.
|
||||
*/
|
||||
int getGender() {
|
||||
return mGender;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server.locales;
|
||||
|
||||
import static android.content.res.Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
@@ -234,7 +236,8 @@ public class LocaleManagerServiceTest {
|
||||
throws Exception {
|
||||
doReturn(DEFAULT_UID).when(mMockPackageManager)
|
||||
.getPackageUidAsUser(anyString(), any(), anyInt());
|
||||
doReturn(new PackageConfig(/* nightMode = */ 0, DEFAULT_LOCALES))
|
||||
doReturn(new PackageConfig(/* nightMode = */ 0, DEFAULT_LOCALES,
|
||||
GRAMMATICAL_GENDER_NOT_SPECIFIED))
|
||||
.when(mMockActivityTaskManager).getApplicationConfig(anyString(), anyInt());
|
||||
String imPkgName = getCurrentInputMethodPackageName();
|
||||
doReturn(Binder.getCallingUid()).when(mMockPackageManager)
|
||||
@@ -274,7 +277,8 @@ public class LocaleManagerServiceTest {
|
||||
doReturn(DEFAULT_UID).when(mMockPackageManager)
|
||||
.getPackageUidAsUser(anyString(), any(), anyInt());
|
||||
setUpPassingPermissionCheckFor(Manifest.permission.READ_APP_SPECIFIC_LOCALES);
|
||||
doReturn(new PackageConfig(/* nightMode = */ 0, /* locales = */ null))
|
||||
doReturn(new PackageConfig(/* nightMode = */ 0, /* locales = */ null,
|
||||
GRAMMATICAL_GENDER_NOT_SPECIFIED))
|
||||
.when(mMockActivityTaskManager).getApplicationConfig(any(), anyInt());
|
||||
|
||||
LocaleList locales = mLocaleManagerService.getApplicationLocales(
|
||||
@@ -288,7 +292,8 @@ public class LocaleManagerServiceTest {
|
||||
throws Exception {
|
||||
doReturn(Binder.getCallingUid()).when(mMockPackageManager)
|
||||
.getPackageUidAsUser(anyString(), any(), anyInt());
|
||||
doReturn(new PackageConfig(/* nightMode = */ 0, DEFAULT_LOCALES))
|
||||
doReturn(new PackageConfig(/* nightMode = */ 0, DEFAULT_LOCALES,
|
||||
GRAMMATICAL_GENDER_NOT_SPECIFIED))
|
||||
.when(mMockActivityTaskManager).getApplicationConfig(anyString(), anyInt());
|
||||
|
||||
LocaleList locales =
|
||||
@@ -303,7 +308,8 @@ public class LocaleManagerServiceTest {
|
||||
doReturn(DEFAULT_UID).when(mMockPackageManager)
|
||||
.getPackageUidAsUser(anyString(), any(), anyInt());
|
||||
setUpPassingPermissionCheckFor(Manifest.permission.READ_APP_SPECIFIC_LOCALES);
|
||||
doReturn(new PackageConfig(/* nightMode = */ 0, DEFAULT_LOCALES))
|
||||
doReturn(new PackageConfig(/* nightMode = */ 0, DEFAULT_LOCALES,
|
||||
GRAMMATICAL_GENDER_NOT_SPECIFIED))
|
||||
.when(mMockActivityTaskManager).getApplicationConfig(anyString(), anyInt());
|
||||
|
||||
LocaleList locales =
|
||||
@@ -319,7 +325,8 @@ public class LocaleManagerServiceTest {
|
||||
.getPackageUidAsUser(eq(DEFAULT_PACKAGE_NAME), any(), anyInt());
|
||||
doReturn(Binder.getCallingUid()).when(mMockPackageManager)
|
||||
.getPackageUidAsUser(eq(DEFAULT_INSTALLER_PACKAGE_NAME), any(), anyInt());
|
||||
doReturn(new PackageConfig(/* nightMode = */ 0, DEFAULT_LOCALES))
|
||||
doReturn(new PackageConfig(/* nightMode = */ 0, DEFAULT_LOCALES,
|
||||
GRAMMATICAL_GENDER_NOT_SPECIFIED))
|
||||
.when(mMockActivityTaskManager).getApplicationConfig(anyString(), anyInt());
|
||||
|
||||
LocaleList locales =
|
||||
@@ -334,7 +341,8 @@ public class LocaleManagerServiceTest {
|
||||
throws Exception {
|
||||
doReturn(DEFAULT_UID).when(mMockPackageManager)
|
||||
.getPackageUidAsUser(anyString(), any(), anyInt());
|
||||
doReturn(new PackageConfig(/* nightMode = */ 0, DEFAULT_LOCALES))
|
||||
doReturn(new PackageConfig(/* nightMode = */ 0, DEFAULT_LOCALES,
|
||||
GRAMMATICAL_GENDER_NOT_SPECIFIED))
|
||||
.when(mMockActivityTaskManager).getApplicationConfig(anyString(), anyInt());
|
||||
String imPkgName = getCurrentInputMethodPackageName();
|
||||
doReturn(Binder.getCallingUid()).when(mMockPackageManager)
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server.locales;
|
||||
|
||||
import static android.content.res.Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
@@ -168,7 +170,8 @@ public class SystemAppUpdateTrackerTest {
|
||||
/* isUpdatedSystemApp = */ true))
|
||||
.when(mMockPackageManager).getApplicationInfo(eq(DEFAULT_PACKAGE_NAME_1), any());
|
||||
doReturn(new ActivityTaskManagerInternal.PackageConfig(/* nightMode = */ 0,
|
||||
DEFAULT_LOCALES)).when(mMockActivityTaskManager)
|
||||
DEFAULT_LOCALES, GRAMMATICAL_GENDER_NOT_SPECIFIED))
|
||||
.when(mMockActivityTaskManager)
|
||||
.getApplicationConfig(anyString(), anyInt());
|
||||
|
||||
mPackageMonitor.onPackageUpdateFinished(DEFAULT_PACKAGE_NAME_1,
|
||||
@@ -186,7 +189,8 @@ public class SystemAppUpdateTrackerTest {
|
||||
/* isUpdatedSystemApp = */ true))
|
||||
.when(mMockPackageManager).getApplicationInfo(eq(DEFAULT_PACKAGE_NAME_1), any());
|
||||
doReturn(new ActivityTaskManagerInternal.PackageConfig(/* nightMode = */ 0,
|
||||
DEFAULT_LOCALES)).when(mMockActivityTaskManager)
|
||||
DEFAULT_LOCALES, GRAMMATICAL_GENDER_NOT_SPECIFIED))
|
||||
.when(mMockActivityTaskManager)
|
||||
.getApplicationConfig(anyString(), anyInt());
|
||||
|
||||
// first update
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.server.wm;
|
||||
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
|
||||
import static android.content.res.Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
|
||||
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
|
||||
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
|
||||
|
||||
@@ -414,9 +415,10 @@ public class WindowProcessControllerTests extends WindowTestsBase {
|
||||
public void testTopActivityUiModeChangeScheduleConfigChange() {
|
||||
final ActivityRecord activity = createActivityRecord(mWpc);
|
||||
activity.setVisibleRequested(true);
|
||||
doReturn(true).when(activity).applyAppSpecificConfig(anyInt(), any());
|
||||
doReturn(true).when(activity).applyAppSpecificConfig(anyInt(), any(), anyInt());
|
||||
mWpc.updateAppSpecificSettingsForAllActivitiesInPackage(DEFAULT_COMPONENT_PACKAGE_NAME,
|
||||
Configuration.UI_MODE_NIGHT_YES, LocaleList.forLanguageTags("en-XA"));
|
||||
Configuration.UI_MODE_NIGHT_YES, LocaleList.forLanguageTags("en-XA"),
|
||||
GRAMMATICAL_GENDER_NOT_SPECIFIED);
|
||||
verify(activity).ensureActivityConfiguration(anyInt(), anyBoolean());
|
||||
}
|
||||
|
||||
@@ -425,8 +427,9 @@ public class WindowProcessControllerTests extends WindowTestsBase {
|
||||
final ActivityRecord activity = createActivityRecord(mWpc);
|
||||
activity.setVisibleRequested(true);
|
||||
mWpc.updateAppSpecificSettingsForAllActivitiesInPackage("com.different.package",
|
||||
Configuration.UI_MODE_NIGHT_YES, LocaleList.forLanguageTags("en-XA"));
|
||||
verify(activity, never()).applyAppSpecificConfig(anyInt(), any());
|
||||
Configuration.UI_MODE_NIGHT_YES, LocaleList.forLanguageTags("en-XA"),
|
||||
GRAMMATICAL_GENDER_NOT_SPECIFIED);
|
||||
verify(activity, never()).applyAppSpecificConfig(anyInt(), any(), anyInt());
|
||||
verify(activity, never()).ensureActivityConfiguration(anyInt(), anyBoolean());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user