Merge "UsbMidiDevice: fix MIDI flush()" into nyc-dev
diff --git a/Android.mk b/Android.mk
index 1469c2c..fc9c319 100644
--- a/Android.mk
+++ b/Android.mk
@@ -197,7 +197,6 @@
core/java/android/net/ICaptivePortal.aidl \
core/java/android/net/IConnectivityManager.aidl \
core/java/android/net/IConnectivityMetricsLogger.aidl \
- core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl \
core/java/android/net/IEthernetManager.aidl \
core/java/android/net/IEthernetServiceListener.aidl \
core/java/android/net/INetworkManagementEventObserver.aidl \
diff --git a/api/current.txt b/api/current.txt
index e4615e9..e4cc11a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -71,6 +71,7 @@
field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
+ field public static final java.lang.String GET_PASSWORD_PRIVILEGED = "android.permission.GET_PASSWORD_PRIVILEGED";
field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
field public static final java.lang.String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH";
field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
@@ -2484,6 +2485,7 @@
field public static final int Widget_Material_CompoundButton_CheckBox = 16974435; // 0x1030263
field public static final int Widget_Material_CompoundButton_RadioButton = 16974436; // 0x1030264
field public static final int Widget_Material_CompoundButton_Star = 16974437; // 0x1030265
+ field public static final int Widget_Material_CompoundButton_Switch = 16974554; // 0x10302da
field public static final int Widget_Material_DatePicker = 16974438; // 0x1030266
field public static final int Widget_Material_DropDownItem = 16974439; // 0x1030267
field public static final int Widget_Material_DropDownItem_Spinner = 16974440; // 0x1030268
@@ -2518,6 +2520,7 @@
field public static final int Widget_Material_Light_CompoundButton_CheckBox = 16974500; // 0x10302a4
field public static final int Widget_Material_Light_CompoundButton_RadioButton = 16974501; // 0x10302a5
field public static final int Widget_Material_Light_CompoundButton_Star = 16974502; // 0x10302a6
+ field public static final int Widget_Material_Light_CompoundButton_Switch = 16974555; // 0x10302db
field public static final int Widget_Material_Light_DatePicker = 16974503; // 0x10302a7
field public static final int Widget_Material_Light_DropDownItem = 16974504; // 0x10302a8
field public static final int Widget_Material_Light_DropDownItem_Spinner = 16974505; // 0x10302a9
@@ -5755,8 +5758,8 @@
field public static final java.lang.String COMMAND_SECONDARY_TAP = "android.wallpaper.secondaryTap";
field public static final java.lang.String COMMAND_TAP = "android.wallpaper.tap";
field public static final java.lang.String EXTRA_LIVE_WALLPAPER_COMPONENT = "android.service.wallpaper.extra.LIVE_WALLPAPER_COMPONENT";
- field public static final int FLAG_SET_LOCK = 2; // 0x2
- field public static final int FLAG_SET_SYSTEM = 1; // 0x1
+ field public static final int FLAG_LOCK = 2; // 0x2
+ field public static final int FLAG_SYSTEM = 1; // 0x1
field public static final java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
}
@@ -5900,6 +5903,7 @@
method public boolean isCallerApplicationRestrictionsManagingPackage();
method public boolean isDeviceOwnerApp(java.lang.String);
method public boolean isLockTaskPermitted(java.lang.String);
+ method public boolean isManagedProfile(android.content.ComponentName);
method public boolean isMasterVolumeMuted(android.content.ComponentName);
method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public boolean isProfileOwnerApp(java.lang.String);
@@ -8519,8 +8523,9 @@
field public static final java.lang.String ACTION_LOCKED_BOOT_COMPLETED = "android.intent.action.LOCKED_BOOT_COMPLETED";
field public static final java.lang.String ACTION_MAIN = "android.intent.action.MAIN";
field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED";
- field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED = "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
+ field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABLE = "android.intent.action.MANAGED_PROFILE_AVAILABLE";
field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED";
+ field public static final java.lang.String ACTION_MANAGED_PROFILE_UNAVAILABLE = "android.intent.action.MANAGED_PROFILE_UNAVAILABLE";
field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
@@ -9915,6 +9920,7 @@
field public static final int PROTECTION_FLAG_PRE23 = 128; // 0x80
field public static final int PROTECTION_FLAG_PREINSTALLED = 1024; // 0x400
field public static final int PROTECTION_FLAG_PRIVILEGED = 16; // 0x10
+ field public static final int PROTECTION_FLAG_SETUP = 2048; // 0x800
field public static final deprecated int PROTECTION_FLAG_SYSTEM = 16; // 0x10
field public static final int PROTECTION_FLAG_VERIFIER = 512; // 0x200
field public static final int PROTECTION_MASK_BASE = 15; // 0xf
@@ -13503,6 +13509,7 @@
public final class Sensor {
method public int getFifoMaxEventCount();
method public int getFifoReservedEventCount();
+ method public int getId();
method public int getMaxDelay();
method public float getMaximumRange();
method public int getMinDelay();
@@ -13512,9 +13519,10 @@
method public float getResolution();
method public java.lang.String getStringType();
method public int getType();
- method public java.util.UUID getUuid();
method public java.lang.String getVendor();
method public int getVersion();
+ method public boolean isAdditionalInfoSupported();
+ method public boolean isDynamicSensor();
method public boolean isWakeUpSensor();
field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0
field public static final int REPORTING_MODE_ONE_SHOT = 2; // 0x2
@@ -13633,8 +13641,9 @@
method public static void getRotationMatrixFromVector(float[], float[]);
method public java.util.List<android.hardware.Sensor> getSensorList(int);
method public deprecated int getSensors();
- method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
- method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback, android.os.Handler);
+ method public boolean isDynamicSensorDiscoverySupported();
+ method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
+ method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback, android.os.Handler);
method public deprecated boolean registerListener(android.hardware.SensorListener, int);
method public deprecated boolean registerListener(android.hardware.SensorListener, int, int);
method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int);
@@ -13643,7 +13652,7 @@
method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, int, android.os.Handler);
method public static boolean remapCoordinateSystem(float[], int, int, float[]);
method public boolean requestTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
- method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
+ method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
method public deprecated void unregisterListener(android.hardware.SensorListener);
method public deprecated void unregisterListener(android.hardware.SensorListener, int);
method public void unregisterListener(android.hardware.SensorEventListener, android.hardware.Sensor);
@@ -13708,8 +13717,8 @@
field public static final float STANDARD_GRAVITY = 9.80665f;
}
- public static abstract class SensorManager.DynamicSensorConnectionCallback {
- ctor public SensorManager.DynamicSensorConnectionCallback();
+ public static abstract class SensorManager.DynamicSensorCallback {
+ ctor public SensorManager.DynamicSensorCallback();
method public void onDynamicSensorConnected(android.hardware.Sensor);
method public void onDynamicSensorDisconnected(android.hardware.Sensor);
}
@@ -19806,7 +19815,7 @@
public static abstract class AudioManager.AudioRecordingCallback {
ctor public AudioManager.AudioRecordingCallback();
- method public void onRecordConfigChanged(android.media.AudioRecordingConfiguration[]);
+ method public void onRecordingConfigChanged(android.media.AudioRecordingConfiguration[]);
}
public static abstract interface AudioManager.OnAudioFocusChangeListener {
@@ -20096,7 +20105,7 @@
field public static final int ORIENTATION_TRANSPOSE = 5; // 0x5
field public static final int ORIENTATION_TRANSVERSE = 7; // 0x7
field public static final int ORIENTATION_UNDEFINED = 0; // 0x0
- field public static final java.lang.String TAG_APERTURE = "FNumber";
+ field public static final deprecated java.lang.String TAG_APERTURE = "FNumber";
field public static final java.lang.String TAG_APERTURE_VALUE = "ApertureValue";
field public static final java.lang.String TAG_ARTIST = "Artist";
field public static final java.lang.String TAG_BITS_PER_SAMPLE = "BitsPerSample";
@@ -20167,7 +20176,7 @@
field public static final java.lang.String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
field public static final java.lang.String TAG_IMAGE_WIDTH = "ImageWidth";
field public static final java.lang.String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex";
- field public static final java.lang.String TAG_ISO = "ISOSpeedRatings";
+ field public static final deprecated java.lang.String TAG_ISO = "ISOSpeedRatings";
field public static final java.lang.String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat";
field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength";
@@ -20575,12 +20584,13 @@
field public static final int DolbyVisionLevelUhd30 = 64; // 0x40
field public static final int DolbyVisionLevelUhd48 = 128; // 0x80
field public static final int DolbyVisionLevelUhd60 = 256; // 0x100
- field public static final int DolbyVisionProfileDvavDen = 2; // 0x2
- field public static final int DolbyVisionProfileDvavDer = 1; // 0x1
- field public static final int DolbyVisionProfileDvheDen = 4; // 0x4
- field public static final int DolbyVisionProfileDvheDer = 3; // 0x3
- field public static final int DolbyVisionProfileDvheDtr = 5; // 0x5
- field public static final int DolbyVisionProfileDvheStn = 6; // 0x6
+ field public static final int DolbyVisionProfileDvavPen = 2; // 0x2
+ field public static final int DolbyVisionProfileDvavPer = 1; // 0x1
+ field public static final int DolbyVisionProfileDvheDen = 8; // 0x8
+ field public static final int DolbyVisionProfileDvheDer = 4; // 0x4
+ field public static final int DolbyVisionProfileDvheDth = 64; // 0x40
+ field public static final int DolbyVisionProfileDvheDtr = 16; // 0x10
+ field public static final int DolbyVisionProfileDvheStn = 32; // 0x20
field public static final int H263Level10 = 1; // 0x1
field public static final int H263Level20 = 2; // 0x2
field public static final int H263Level30 = 4; // 0x4
@@ -28707,6 +28717,7 @@
field public static final int TEMPERATURE_CURRENT = 0; // 0x0
field public static final int TEMPERATURE_SHUTDOWN = 2; // 0x2
field public static final int TEMPERATURE_THROTTLING = 1; // 0x1
+ field public static final int TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3; // 0x3
field public static final float UNDEFINED_TEMPERATURE = -3.4028235E38f;
}
@@ -29066,6 +29077,7 @@
method public boolean isInteractive();
method public boolean isPowerSaveMode();
method public deprecated boolean isScreenOn();
+ method public boolean isSustainedPerformanceModeSupported();
method public boolean isWakeLockLevelSupported(int);
method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
method public void reboot(java.lang.String);
@@ -29692,7 +29704,6 @@
method protected void onClick();
method protected android.view.View onCreateView(android.view.ViewGroup);
method public void onDependencyChanged(android.preference.Preference, boolean);
- method protected void onDetachedFromActivity();
method protected java.lang.Object onGetDefaultValue(android.content.res.TypedArray, int);
method public void onParentChanged(android.preference.Preference, boolean);
method protected void onPrepareForRemoval();
@@ -36722,6 +36733,7 @@
field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
+ field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
field public static final java.lang.String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
field public static final java.lang.String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
field public static final java.lang.String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
@@ -37298,7 +37310,8 @@
method public java.lang.String getDeviceSoftwareVersion();
method public java.lang.String getGroupIdLevel1();
method public java.lang.String getGroupIdLevel1(int);
- method public java.lang.String getIccSimChallengeResponse(int, java.lang.String);
+ method public java.lang.String getIccAuthentication(int, int, java.lang.String);
+ method public java.lang.String getIccAuthentication(int, int, int, java.lang.String);
method public java.lang.String getLine1AlphaTag(int);
method public java.lang.String getLine1Number();
method public java.lang.String getLine1Number(int);
@@ -37367,6 +37380,13 @@
field public static final java.lang.String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL";
field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
+ field public static final int APPTYPE_CSIM = 4; // 0x4
+ field public static final int APPTYPE_ISIM = 5; // 0x5
+ field public static final int APPTYPE_RUIM = 3; // 0x3
+ field public static final int APPTYPE_SIM = 1; // 0x1
+ field public static final int APPTYPE_USIM = 2; // 0x2
+ field public static final int AUTHTYPE_EAP_AKA = 129; // 0x81
+ field public static final int AUTHTYPE_EAP_SIM = 128; // 0x80
field public static final int CALL_STATE_IDLE = 0; // 0x0
field public static final int CALL_STATE_OFFHOOK = 2; // 0x2
field public static final int CALL_STATE_RINGING = 1; // 0x1
@@ -42264,6 +42284,7 @@
method public boolean dispatchDragEvent(android.view.DragEvent);
method protected void dispatchDraw(android.graphics.Canvas);
method public void dispatchDrawableHotspotChanged(float, float);
+ method public void dispatchFinishTemporaryDetach();
method protected boolean dispatchGenericFocusedEvent(android.view.MotionEvent);
method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
method protected boolean dispatchGenericPointerEvent(android.view.MotionEvent);
@@ -42283,6 +42304,7 @@
method protected void dispatchSetActivated(boolean);
method protected void dispatchSetPressed(boolean);
method protected void dispatchSetSelected(boolean);
+ method public void dispatchStartTemporaryDetach();
method public void dispatchSystemUiVisibilityChanged(int);
method public boolean dispatchTouchEvent(android.view.MotionEvent);
method public boolean dispatchTrackballEvent(android.view.MotionEvent);
@@ -42495,6 +42517,7 @@
method public boolean isSelected();
method public boolean isShown();
method public boolean isSoundEffectsEnabled();
+ method public final boolean isTemporarilyDetached();
method public boolean isTextAlignmentResolved();
method public boolean isTextDirectionResolved();
method public boolean isVerticalFadingEdgeEnabled();
@@ -44251,6 +44274,7 @@
public final class AccessibilityWindowInfo implements android.os.Parcelable {
method public int describeContents();
+ method public android.view.accessibility.AccessibilityNodeInfo getAnchor();
method public void getBoundsInScreen(android.graphics.Rect);
method public android.view.accessibility.AccessibilityWindowInfo getChild(int);
method public int getChildCount();
@@ -44258,6 +44282,7 @@
method public int getLayer();
method public android.view.accessibility.AccessibilityWindowInfo getParent();
method public android.view.accessibility.AccessibilityNodeInfo getRoot();
+ method public java.lang.CharSequence getTitle();
method public int getType();
method public boolean isAccessibilityFocused();
method public boolean isActive();
@@ -49260,9 +49285,7 @@
public final class FilePermission extends java.security.Permission implements java.io.Serializable {
ctor public FilePermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -50001,6 +50024,7 @@
method public static int compare(boolean, boolean);
method public int compareTo(java.lang.Boolean);
method public static boolean getBoolean(java.lang.String);
+ method public static int hashCode(boolean);
method public static boolean parseBoolean(java.lang.String);
method public static java.lang.String toString(boolean);
method public static java.lang.Boolean valueOf(boolean);
@@ -50018,6 +50042,7 @@
method public static java.lang.Byte decode(java.lang.String) throws java.lang.NumberFormatException;
method public double doubleValue();
method public float floatValue();
+ method public static int hashCode(byte);
method public int intValue();
method public long longValue();
method public static byte parseByte(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -50026,6 +50051,7 @@
method public static java.lang.Byte valueOf(byte);
method public static java.lang.Byte valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
method public static java.lang.Byte valueOf(java.lang.String) throws java.lang.NumberFormatException;
+ field public static final int BYTES = 1; // 0x1
field public static final byte MAX_VALUE = 127; // 0x7f
field public static final byte MIN_VALUE = -128; // 0xffffff80
field public static final int SIZE = 8; // 0x8
@@ -50063,6 +50089,7 @@
method public static int getNumericValue(int);
method public static int getType(char);
method public static int getType(int);
+ method public static int hashCode(char);
method public static char highSurrogate(int);
method public static boolean isAlphabetic(int);
method public static boolean isBmpCodePoint(int);
@@ -50123,6 +50150,7 @@
method public static char toUpperCase(char);
method public static int toUpperCase(int);
method public static java.lang.Character valueOf(char);
+ field public static final int BYTES = 2; // 0x2
field public static final byte COMBINING_SPACING_MARK = 8; // 0x8
field public static final byte CONNECTOR_PUNCTUATION = 23; // 0x17
field public static final byte CONTROL = 15; // 0xf
@@ -50749,6 +50777,7 @@
method public static int floatToIntBits(float);
method public static int floatToRawIntBits(float);
method public float floatValue();
+ method public static int hashCode(float);
method public static float intBitsToFloat(int);
method public int intValue();
method public static boolean isFinite(float);
@@ -50757,11 +50786,15 @@
method public static boolean isNaN(float);
method public boolean isNaN();
method public long longValue();
+ method public static float max(float, float);
+ method public static float min(float, float);
method public static float parseFloat(java.lang.String) throws java.lang.NumberFormatException;
+ method public static float sum(float, float);
method public static java.lang.String toHexString(float);
method public static java.lang.String toString(float);
method public static java.lang.Float valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Float valueOf(float);
+ field public static final int BYTES = 4; // 0x4
field public static final int MAX_EXPONENT = 127; // 0x7f
field public static final float MAX_VALUE = 3.4028235E38f;
field public static final int MIN_EXPONENT = -126; // 0xffffff82
@@ -50941,6 +50974,7 @@
method public static java.lang.Long valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
method public static java.lang.Long valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Long valueOf(long);
+ field public static final int BYTES = 8; // 0x8
field public static final long MAX_VALUE = 9223372036854775807L; // 0x7fffffffffffffffL
field public static final long MIN_VALUE = -9223372036854775808L; // 0x8000000000000000L
field public static final int SIZE = 64; // 0x40
@@ -51244,6 +51278,7 @@
method public static java.lang.Short decode(java.lang.String) throws java.lang.NumberFormatException;
method public double doubleValue();
method public float floatValue();
+ method public static int hashCode(short);
method public int intValue();
method public long longValue();
method public static short parseShort(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -51253,6 +51288,7 @@
method public static java.lang.Short valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
method public static java.lang.Short valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Short valueOf(short);
+ field public static final int BYTES = 2; // 0x2
field public static final short MAX_VALUE = 32767; // 0x7fff
field public static final short MIN_VALUE = -32768; // 0xffff8000
field public static final int SIZE = 16; // 0x10
@@ -52776,9 +52812,7 @@
public final class SocketPermission extends java.security.Permission implements java.io.Serializable {
ctor public SocketPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -53860,9 +53894,7 @@
public final class AllPermission extends java.security.Permission {
ctor public AllPermission();
ctor public AllPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -53876,9 +53908,7 @@
public abstract class BasicPermission extends java.security.Permission implements java.io.Serializable {
ctor public BasicPermission(java.lang.String);
ctor public BasicPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -54256,10 +54286,8 @@
public abstract class Permission implements java.security.Guard java.io.Serializable {
ctor public Permission(java.lang.String);
method public void checkGuard(java.lang.Object) throws java.lang.SecurityException;
- method public abstract boolean equals(java.lang.Object);
method public abstract java.lang.String getActions();
method public final java.lang.String getName();
- method public abstract int hashCode();
method public abstract boolean implies(java.security.Permission);
method public java.security.PermissionCollection newPermissionCollection();
}
@@ -54517,13 +54545,11 @@
public final class UnresolvedPermission extends java.security.Permission implements java.io.Serializable {
ctor public UnresolvedPermission(java.lang.String, java.lang.String, java.lang.String, java.security.cert.Certificate[]);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
method public java.lang.String getUnresolvedActions();
method public java.security.cert.Certificate[] getUnresolvedCerts();
method public java.lang.String getUnresolvedName();
method public java.lang.String getUnresolvedType();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -54581,8 +54607,6 @@
}
public abstract interface Permission {
- method public abstract boolean equals(java.lang.Object);
- method public abstract java.lang.String toString();
}
}
@@ -63891,11 +63915,9 @@
public final class PrivateCredentialPermission extends java.security.Permission {
ctor public PrivateCredentialPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
method public java.lang.String getCredentialClass();
method public java.lang.String[][] getPrincipals();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
diff --git a/api/removed.txt b/api/removed.txt
index 86085c8..3f16bca 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -94,6 +94,10 @@
package android.media.tv {
+ public final class TvInputManager {
+ method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
+ }
+
public class TvView extends android.view.ViewGroup {
method public void requestUnblockContent(android.media.tv.TvContentRating);
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 087b2506..f63d2ac 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -103,6 +103,7 @@
field public static final java.lang.String GET_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS";
field public static final java.lang.String GET_PACKAGE_IMPORTANCE = "android.permission.GET_PACKAGE_IMPORTANCE";
field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
+ field public static final java.lang.String GET_PASSWORD_PRIVILEGED = "android.permission.GET_PASSWORD_PRIVILEGED";
field public static final java.lang.String GET_PROCESS_STATE_AND_OOM_SCORE = "android.permission.GET_PROCESS_STATE_AND_OOM_SCORE";
field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
field public static final java.lang.String GET_TOP_ACTIVITY_INFO = "android.permission.GET_TOP_ACTIVITY_INFO";
@@ -2587,6 +2588,7 @@
field public static final int Widget_Material_CompoundButton_CheckBox = 16974435; // 0x1030263
field public static final int Widget_Material_CompoundButton_RadioButton = 16974436; // 0x1030264
field public static final int Widget_Material_CompoundButton_Star = 16974437; // 0x1030265
+ field public static final int Widget_Material_CompoundButton_Switch = 16974554; // 0x10302da
field public static final int Widget_Material_DatePicker = 16974438; // 0x1030266
field public static final int Widget_Material_DropDownItem = 16974439; // 0x1030267
field public static final int Widget_Material_DropDownItem_Spinner = 16974440; // 0x1030268
@@ -2621,6 +2623,7 @@
field public static final int Widget_Material_Light_CompoundButton_CheckBox = 16974500; // 0x10302a4
field public static final int Widget_Material_Light_CompoundButton_RadioButton = 16974501; // 0x10302a5
field public static final int Widget_Material_Light_CompoundButton_Star = 16974502; // 0x10302a6
+ field public static final int Widget_Material_Light_CompoundButton_Switch = 16974555; // 0x10302db
field public static final int Widget_Material_Light_DatePicker = 16974503; // 0x10302a7
field public static final int Widget_Material_Light_DropDownItem = 16974504; // 0x10302a8
field public static final int Widget_Material_Light_DropDownItem_Spinner = 16974505; // 0x10302a9
@@ -5893,8 +5896,8 @@
field public static final java.lang.String COMMAND_SECONDARY_TAP = "android.wallpaper.secondaryTap";
field public static final java.lang.String COMMAND_TAP = "android.wallpaper.tap";
field public static final java.lang.String EXTRA_LIVE_WALLPAPER_COMPONENT = "android.service.wallpaper.extra.LIVE_WALLPAPER_COMPONENT";
- field public static final int FLAG_SET_LOCK = 2; // 0x2
- field public static final int FLAG_SET_SYSTEM = 1; // 0x1
+ field public static final int FLAG_LOCK = 2; // 0x2
+ field public static final int FLAG_SYSTEM = 1; // 0x1
field public static final java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
}
@@ -6047,6 +6050,7 @@
method public boolean isCallerApplicationRestrictionsManagingPackage();
method public boolean isDeviceOwnerApp(java.lang.String);
method public boolean isLockTaskPermitted(java.lang.String);
+ method public boolean isManagedProfile(android.content.ComponentName);
method public boolean isMasterVolumeMuted(android.content.ComponentName);
method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public boolean isProfileOwnerApp(java.lang.String);
@@ -8835,8 +8839,9 @@
field public static final java.lang.String ACTION_LOCKED_BOOT_COMPLETED = "android.intent.action.LOCKED_BOOT_COMPLETED";
field public static final java.lang.String ACTION_MAIN = "android.intent.action.MAIN";
field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED";
- field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED = "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
+ field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABLE = "android.intent.action.MANAGED_PROFILE_AVAILABLE";
field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED";
+ field public static final java.lang.String ACTION_MANAGED_PROFILE_UNAVAILABLE = "android.intent.action.MANAGED_PROFILE_UNAVAILABLE";
field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
@@ -10314,6 +10319,7 @@
field public static final int PROTECTION_FLAG_PRE23 = 128; // 0x80
field public static final int PROTECTION_FLAG_PREINSTALLED = 1024; // 0x400
field public static final int PROTECTION_FLAG_PRIVILEGED = 16; // 0x10
+ field public static final int PROTECTION_FLAG_SETUP = 2048; // 0x800
field public static final deprecated int PROTECTION_FLAG_SYSTEM = 16; // 0x10
field public static final int PROTECTION_FLAG_VERIFIER = 512; // 0x200
field public static final int PROTECTION_MASK_BASE = 15; // 0xf
@@ -13902,6 +13908,7 @@
public final class Sensor {
method public int getFifoMaxEventCount();
method public int getFifoReservedEventCount();
+ method public int getId();
method public int getMaxDelay();
method public float getMaximumRange();
method public int getMinDelay();
@@ -13914,7 +13921,9 @@
method public java.util.UUID getUuid();
method public java.lang.String getVendor();
method public int getVersion();
+ method public boolean isAdditionalInfoSupported();
method public boolean isDataInjectionSupported();
+ method public boolean isDynamicSensor();
method public boolean isWakeUpSensor();
field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0
field public static final int REPORTING_MODE_ONE_SHOT = 2; // 0x2
@@ -14039,8 +14048,9 @@
method public deprecated int getSensors();
method public boolean initDataInjection(boolean);
method public boolean injectSensorData(android.hardware.Sensor, float[], int, long);
- method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
- method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback, android.os.Handler);
+ method public boolean isDynamicSensorDiscoverySupported();
+ method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
+ method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback, android.os.Handler);
method public deprecated boolean registerListener(android.hardware.SensorListener, int);
method public deprecated boolean registerListener(android.hardware.SensorListener, int, int);
method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int);
@@ -14049,7 +14059,7 @@
method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, int, android.os.Handler);
method public static boolean remapCoordinateSystem(float[], int, int, float[]);
method public boolean requestTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
- method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
+ method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
method public deprecated void unregisterListener(android.hardware.SensorListener);
method public deprecated void unregisterListener(android.hardware.SensorListener, int);
method public void unregisterListener(android.hardware.SensorEventListener, android.hardware.Sensor);
@@ -14114,8 +14124,8 @@
field public static final float STANDARD_GRAVITY = 9.80665f;
}
- public static abstract class SensorManager.DynamicSensorConnectionCallback {
- ctor public SensorManager.DynamicSensorConnectionCallback();
+ public static abstract class SensorManager.DynamicSensorCallback {
+ ctor public SensorManager.DynamicSensorCallback();
method public void onDynamicSensorConnected(android.hardware.Sensor);
method public void onDynamicSensorDisconnected(android.hardware.Sensor);
}
@@ -15264,6 +15274,7 @@
ctor public ContextHubInfo();
method public int describeContents();
method public int getId();
+ method public int getMaxPacketLengthBytes();
method public android.hardware.location.MemoryRegion[] getMemoryRegions();
method public java.lang.String getName();
method public float getPeakMips();
@@ -15291,10 +15302,6 @@
method public int sendMessage(int, int, android.hardware.location.ContextHubMessage);
method public int unloadNanoApp(int);
method public int unregisterCallback(android.hardware.location.ContextHubManager.Callback);
- field public static final int ANY_HUB = -1; // 0xffffffff
- field public static final int MSG_DATA_SEND = 3; // 0x3
- field public static final int MSG_LOAD_NANO_APP = 1; // 0x1
- field public static final int MSG_UNLOAD_NANO_APP = 2; // 0x2
}
public static abstract class ContextHubManager.Callback {
@@ -15488,7 +15495,7 @@
public class NanoAppInstanceInfo {
ctor public NanoAppInstanceInfo();
method public int describeContents();
- method public int getAppId();
+ method public long getAppId();
method public int getAppVersion();
method public int getContexthubId();
method public int getHandle();
@@ -15499,17 +15506,6 @@
method public int getNeededWriteMemBytes();
method public int[] getOutputEvents();
method public java.lang.String getPublisher();
- method public void setAppId(int);
- method public void setAppVersion(int);
- method public void setContexthubId(int);
- method public void setHandle(int);
- method public void setName(java.lang.String);
- method public void setNeededExecMemBytes(int);
- method public void setNeededReadMemBytes(int);
- method public void setNeededSensors(int[]);
- method public void setNeededWriteMemBytes(int);
- method public void setOutputEvents(int[]);
- method public void setPublisher(java.lang.String);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppInstanceInfo> CREATOR;
}
@@ -21295,7 +21291,7 @@
public static abstract class AudioManager.AudioRecordingCallback {
ctor public AudioManager.AudioRecordingCallback();
- method public void onRecordConfigChanged(android.media.AudioRecordingConfiguration[]);
+ method public void onRecordingConfigChanged(android.media.AudioRecordingConfiguration[]);
}
public static abstract interface AudioManager.OnAudioFocusChangeListener {
@@ -21588,7 +21584,7 @@
field public static final int ORIENTATION_TRANSPOSE = 5; // 0x5
field public static final int ORIENTATION_TRANSVERSE = 7; // 0x7
field public static final int ORIENTATION_UNDEFINED = 0; // 0x0
- field public static final java.lang.String TAG_APERTURE = "FNumber";
+ field public static final deprecated java.lang.String TAG_APERTURE = "FNumber";
field public static final java.lang.String TAG_APERTURE_VALUE = "ApertureValue";
field public static final java.lang.String TAG_ARTIST = "Artist";
field public static final java.lang.String TAG_BITS_PER_SAMPLE = "BitsPerSample";
@@ -21659,7 +21655,7 @@
field public static final java.lang.String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
field public static final java.lang.String TAG_IMAGE_WIDTH = "ImageWidth";
field public static final java.lang.String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex";
- field public static final java.lang.String TAG_ISO = "ISOSpeedRatings";
+ field public static final deprecated java.lang.String TAG_ISO = "ISOSpeedRatings";
field public static final java.lang.String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat";
field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength";
@@ -22067,12 +22063,13 @@
field public static final int DolbyVisionLevelUhd30 = 64; // 0x40
field public static final int DolbyVisionLevelUhd48 = 128; // 0x80
field public static final int DolbyVisionLevelUhd60 = 256; // 0x100
- field public static final int DolbyVisionProfileDvavDen = 2; // 0x2
- field public static final int DolbyVisionProfileDvavDer = 1; // 0x1
- field public static final int DolbyVisionProfileDvheDen = 4; // 0x4
- field public static final int DolbyVisionProfileDvheDer = 3; // 0x3
- field public static final int DolbyVisionProfileDvheDtr = 5; // 0x5
- field public static final int DolbyVisionProfileDvheStn = 6; // 0x6
+ field public static final int DolbyVisionProfileDvavPen = 2; // 0x2
+ field public static final int DolbyVisionProfileDvavPer = 1; // 0x1
+ field public static final int DolbyVisionProfileDvheDen = 8; // 0x8
+ field public static final int DolbyVisionProfileDvheDer = 4; // 0x4
+ field public static final int DolbyVisionProfileDvheDth = 64; // 0x40
+ field public static final int DolbyVisionProfileDvheDtr = 16; // 0x10
+ field public static final int DolbyVisionProfileDvheStn = 32; // 0x20
field public static final int H263Level10 = 1; // 0x1
field public static final int H263Level20 = 2; // 0x2
field public static final int H263Level30 = 4; // 0x4
@@ -24624,6 +24621,7 @@
method public android.media.tv.TvInputInfo.Builder setHdmiDeviceInfo(android.hardware.hdmi.HdmiDeviceInfo);
method public android.media.tv.TvInputInfo.Builder setIcon(android.graphics.drawable.Icon);
method public android.media.tv.TvInputInfo.Builder setIcon(android.graphics.drawable.Icon, int);
+ method public android.media.tv.TvInputInfo.Builder setLabel(java.lang.CharSequence);
method public android.media.tv.TvInputInfo.Builder setLabel(int);
method public android.media.tv.TvInputInfo.Builder setParentId(java.lang.String);
method public android.media.tv.TvInputInfo.Builder setTunerCount(int);
@@ -24638,7 +24636,7 @@
}
public final class TvInputManager {
- method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
+ method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputInfo, android.media.tv.TvInputManager.HardwareCallback);
method public void addBlockedRating(android.media.tv.TvContentRating);
method public boolean captureFrame(java.lang.String, android.view.Surface, android.media.tv.TvStreamConfig);
method public java.util.List<android.media.tv.TvStreamConfig> getAvailableTvStreamConfigList(java.lang.String);
@@ -30951,6 +30949,7 @@
field public static final int TEMPERATURE_CURRENT = 0; // 0x0
field public static final int TEMPERATURE_SHUTDOWN = 2; // 0x2
field public static final int TEMPERATURE_THROTTLING = 1; // 0x1
+ field public static final int TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3; // 0x3
field public static final float UNDEFINED_TEMPERATURE = -3.4028235E38f;
}
@@ -31311,6 +31310,7 @@
method public boolean isPowerSaveMode();
method public boolean isScreenBrightnessBoosted();
method public deprecated boolean isScreenOn();
+ method public boolean isSustainedPerformanceModeSupported();
method public boolean isWakeLockLevelSupported(int);
method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
method public void reboot(java.lang.String);
@@ -31326,8 +31326,8 @@
field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
- field public static final int USER_ACTIVITY_EVENT_ACCESSIBILITY = 3; // 0x3
field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
+ field public static final int USER_ACTIVITY_EVENT_ACCESSIBILITY = 3; // 0x3
field public static final int USER_ACTIVITY_EVENT_BUTTON = 1; // 0x1
field public static final int USER_ACTIVITY_EVENT_OTHER = 0; // 0x0
field public static final int USER_ACTIVITY_EVENT_TOUCH = 2; // 0x2
@@ -32008,7 +32008,6 @@
method protected void onClick();
method protected android.view.View onCreateView(android.view.ViewGroup);
method public void onDependencyChanged(android.preference.Preference, boolean);
- method protected void onDetachedFromActivity();
method protected java.lang.Object onGetDefaultValue(android.content.res.TypedArray, int);
method public void onParentChanged(android.preference.Preference, boolean);
method protected void onPrepareForRemoval();
@@ -32670,7 +32669,6 @@
method public final android.os.IBinder onBind(android.content.Intent);
method public abstract void onConnected();
method public abstract void onDisconnected();
- method public final boolean onUnbind(android.content.Intent);
method public final void updateRecommendations(java.util.List<android.printservice.recommendation.RecommendationInfo>);
}
@@ -39411,6 +39409,7 @@
field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
+ field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
field public static final java.lang.String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
field public static final java.lang.String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
field public static final java.lang.String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
@@ -40006,7 +40005,8 @@
method public java.lang.String getDeviceSoftwareVersion();
method public java.lang.String getGroupIdLevel1();
method public java.lang.String getGroupIdLevel1(int);
- method public java.lang.String getIccSimChallengeResponse(int, java.lang.String);
+ method public java.lang.String getIccAuthentication(int, int, java.lang.String);
+ method public java.lang.String getIccAuthentication(int, int, int, java.lang.String);
method public java.lang.String getLine1AlphaTag(int);
method public java.lang.String getLine1Number();
method public java.lang.String getLine1Number(int);
@@ -40096,6 +40096,13 @@
field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
field public static final java.lang.String ACTION_SHOW_VOICEMAIL_NOTIFICATION = "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION";
+ field public static final int APPTYPE_CSIM = 4; // 0x4
+ field public static final int APPTYPE_ISIM = 5; // 0x5
+ field public static final int APPTYPE_RUIM = 3; // 0x3
+ field public static final int APPTYPE_SIM = 1; // 0x1
+ field public static final int APPTYPE_USIM = 2; // 0x2
+ field public static final int AUTHTYPE_EAP_AKA = 129; // 0x81
+ field public static final int AUTHTYPE_EAP_SIM = 128; // 0x80
field public static final int CALL_STATE_IDLE = 0; // 0x0
field public static final int CALL_STATE_OFFHOOK = 2; // 0x2
field public static final int CALL_STATE_RINGING = 1; // 0x1
@@ -45017,6 +45024,7 @@
method public boolean dispatchDragEvent(android.view.DragEvent);
method protected void dispatchDraw(android.graphics.Canvas);
method public void dispatchDrawableHotspotChanged(float, float);
+ method public void dispatchFinishTemporaryDetach();
method protected boolean dispatchGenericFocusedEvent(android.view.MotionEvent);
method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
method protected boolean dispatchGenericPointerEvent(android.view.MotionEvent);
@@ -45036,6 +45044,7 @@
method protected void dispatchSetActivated(boolean);
method protected void dispatchSetPressed(boolean);
method protected void dispatchSetSelected(boolean);
+ method public void dispatchStartTemporaryDetach();
method public void dispatchSystemUiVisibilityChanged(int);
method public boolean dispatchTouchEvent(android.view.MotionEvent);
method public boolean dispatchTrackballEvent(android.view.MotionEvent);
@@ -45248,6 +45257,7 @@
method public boolean isSelected();
method public boolean isShown();
method public boolean isSoundEffectsEnabled();
+ method public final boolean isTemporarilyDetached();
method public boolean isTextAlignmentResolved();
method public boolean isTextDirectionResolved();
method public boolean isVerticalFadingEdgeEnabled();
@@ -47007,6 +47017,7 @@
public final class AccessibilityWindowInfo implements android.os.Parcelable {
method public int describeContents();
+ method public android.view.accessibility.AccessibilityNodeInfo getAnchor();
method public void getBoundsInScreen(android.graphics.Rect);
method public android.view.accessibility.AccessibilityWindowInfo getChild(int);
method public int getChildCount();
@@ -47014,6 +47025,7 @@
method public int getLayer();
method public android.view.accessibility.AccessibilityWindowInfo getParent();
method public android.view.accessibility.AccessibilityNodeInfo getRoot();
+ method public java.lang.CharSequence getTitle();
method public int getType();
method public boolean isAccessibilityFocused();
method public boolean isActive();
@@ -48649,6 +48661,7 @@
method public int getPackageId(android.content.res.Resources, java.lang.String);
method public void invokeDrawGlFunctor(android.view.View, long, boolean);
method public boolean isTraceTagEnabled();
+ method public java.lang.Runnable setDrawGlFunctionDetachedCallback(android.view.View, java.lang.Runnable);
method public void setOnTraceEnabledChangeListener(android.webkit.WebViewDelegate.OnTraceEnabledChangeListener);
}
@@ -48854,6 +48867,24 @@
method public abstract boolean shouldDelayChildPressedState();
}
+ public final class WebViewProviderInfo implements android.os.Parcelable {
+ ctor public WebViewProviderInfo(java.lang.String, java.lang.String, boolean, boolean, java.lang.String[]);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.webkit.WebViewProviderInfo> CREATOR;
+ field public final boolean availableByDefault;
+ field public final java.lang.String description;
+ field public final boolean isFallback;
+ field public final java.lang.String packageName;
+ field public final java.lang.String[] signatures;
+ }
+
+ public final class WebViewUpdateService {
+ method public static android.webkit.WebViewProviderInfo[] getAllWebViewPackages();
+ method public static java.lang.String getCurrentWebViewPackageName();
+ method public static android.webkit.WebViewProviderInfo[] getValidWebViewPackages();
+ }
+
}
package android.widget {
@@ -52351,9 +52382,7 @@
public final class FilePermission extends java.security.Permission implements java.io.Serializable {
ctor public FilePermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -53092,6 +53121,7 @@
method public static int compare(boolean, boolean);
method public int compareTo(java.lang.Boolean);
method public static boolean getBoolean(java.lang.String);
+ method public static int hashCode(boolean);
method public static boolean parseBoolean(java.lang.String);
method public static java.lang.String toString(boolean);
method public static java.lang.Boolean valueOf(boolean);
@@ -53109,6 +53139,7 @@
method public static java.lang.Byte decode(java.lang.String) throws java.lang.NumberFormatException;
method public double doubleValue();
method public float floatValue();
+ method public static int hashCode(byte);
method public int intValue();
method public long longValue();
method public static byte parseByte(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -53117,6 +53148,7 @@
method public static java.lang.Byte valueOf(byte);
method public static java.lang.Byte valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
method public static java.lang.Byte valueOf(java.lang.String) throws java.lang.NumberFormatException;
+ field public static final int BYTES = 1; // 0x1
field public static final byte MAX_VALUE = 127; // 0x7f
field public static final byte MIN_VALUE = -128; // 0xffffff80
field public static final int SIZE = 8; // 0x8
@@ -53154,6 +53186,7 @@
method public static int getNumericValue(int);
method public static int getType(char);
method public static int getType(int);
+ method public static int hashCode(char);
method public static char highSurrogate(int);
method public static boolean isAlphabetic(int);
method public static boolean isBmpCodePoint(int);
@@ -53214,6 +53247,7 @@
method public static char toUpperCase(char);
method public static int toUpperCase(int);
method public static java.lang.Character valueOf(char);
+ field public static final int BYTES = 2; // 0x2
field public static final byte COMBINING_SPACING_MARK = 8; // 0x8
field public static final byte CONNECTOR_PUNCTUATION = 23; // 0x17
field public static final byte CONTROL = 15; // 0xf
@@ -53840,6 +53874,7 @@
method public static int floatToIntBits(float);
method public static int floatToRawIntBits(float);
method public float floatValue();
+ method public static int hashCode(float);
method public static float intBitsToFloat(int);
method public int intValue();
method public static boolean isFinite(float);
@@ -53848,11 +53883,15 @@
method public static boolean isNaN(float);
method public boolean isNaN();
method public long longValue();
+ method public static float max(float, float);
+ method public static float min(float, float);
method public static float parseFloat(java.lang.String) throws java.lang.NumberFormatException;
+ method public static float sum(float, float);
method public static java.lang.String toHexString(float);
method public static java.lang.String toString(float);
method public static java.lang.Float valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Float valueOf(float);
+ field public static final int BYTES = 4; // 0x4
field public static final int MAX_EXPONENT = 127; // 0x7f
field public static final float MAX_VALUE = 3.4028235E38f;
field public static final int MIN_EXPONENT = -126; // 0xffffff82
@@ -54032,6 +54071,7 @@
method public static java.lang.Long valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
method public static java.lang.Long valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Long valueOf(long);
+ field public static final int BYTES = 8; // 0x8
field public static final long MAX_VALUE = 9223372036854775807L; // 0x7fffffffffffffffL
field public static final long MIN_VALUE = -9223372036854775808L; // 0x8000000000000000L
field public static final int SIZE = 64; // 0x40
@@ -54335,6 +54375,7 @@
method public static java.lang.Short decode(java.lang.String) throws java.lang.NumberFormatException;
method public double doubleValue();
method public float floatValue();
+ method public static int hashCode(short);
method public int intValue();
method public long longValue();
method public static short parseShort(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -54344,6 +54385,7 @@
method public static java.lang.Short valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
method public static java.lang.Short valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Short valueOf(short);
+ field public static final int BYTES = 2; // 0x2
field public static final short MAX_VALUE = 32767; // 0x7fff
field public static final short MIN_VALUE = -32768; // 0xffff8000
field public static final int SIZE = 16; // 0x10
@@ -55867,9 +55909,7 @@
public final class SocketPermission extends java.security.Permission implements java.io.Serializable {
ctor public SocketPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -56951,9 +56991,7 @@
public final class AllPermission extends java.security.Permission {
ctor public AllPermission();
ctor public AllPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -56967,9 +57005,7 @@
public abstract class BasicPermission extends java.security.Permission implements java.io.Serializable {
ctor public BasicPermission(java.lang.String);
ctor public BasicPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -57347,10 +57383,8 @@
public abstract class Permission implements java.security.Guard java.io.Serializable {
ctor public Permission(java.lang.String);
method public void checkGuard(java.lang.Object) throws java.lang.SecurityException;
- method public abstract boolean equals(java.lang.Object);
method public abstract java.lang.String getActions();
method public final java.lang.String getName();
- method public abstract int hashCode();
method public abstract boolean implies(java.security.Permission);
method public java.security.PermissionCollection newPermissionCollection();
}
@@ -57608,13 +57642,11 @@
public final class UnresolvedPermission extends java.security.Permission implements java.io.Serializable {
ctor public UnresolvedPermission(java.lang.String, java.lang.String, java.lang.String, java.security.cert.Certificate[]);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
method public java.lang.String getUnresolvedActions();
method public java.security.cert.Certificate[] getUnresolvedCerts();
method public java.lang.String getUnresolvedName();
method public java.lang.String getUnresolvedType();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -57672,8 +57704,6 @@
}
public abstract interface Permission {
- method public abstract boolean equals(java.lang.Object);
- method public abstract java.lang.String toString();
}
}
@@ -66982,11 +67012,9 @@
public final class PrivateCredentialPermission extends java.security.Permission {
ctor public PrivateCredentialPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
method public java.lang.String getCredentialClass();
method public java.lang.String[][] getPrincipals();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
diff --git a/api/system-removed.txt b/api/system-removed.txt
index bc17627..03cf8b0 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -92,6 +92,10 @@
package android.media.tv {
+ public final class TvInputManager {
+ method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
+ }
+
public class TvView extends android.view.ViewGroup {
method public void requestUnblockContent(android.media.tv.TvContentRating);
}
diff --git a/api/test-current.txt b/api/test-current.txt
index fac2219..d495d9f 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -71,6 +71,7 @@
field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
+ field public static final java.lang.String GET_PASSWORD_PRIVILEGED = "android.permission.GET_PASSWORD_PRIVILEGED";
field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
field public static final java.lang.String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH";
field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
@@ -2484,6 +2485,7 @@
field public static final int Widget_Material_CompoundButton_CheckBox = 16974435; // 0x1030263
field public static final int Widget_Material_CompoundButton_RadioButton = 16974436; // 0x1030264
field public static final int Widget_Material_CompoundButton_Star = 16974437; // 0x1030265
+ field public static final int Widget_Material_CompoundButton_Switch = 16974554; // 0x10302da
field public static final int Widget_Material_DatePicker = 16974438; // 0x1030266
field public static final int Widget_Material_DropDownItem = 16974439; // 0x1030267
field public static final int Widget_Material_DropDownItem_Spinner = 16974440; // 0x1030268
@@ -2518,6 +2520,7 @@
field public static final int Widget_Material_Light_CompoundButton_CheckBox = 16974500; // 0x10302a4
field public static final int Widget_Material_Light_CompoundButton_RadioButton = 16974501; // 0x10302a5
field public static final int Widget_Material_Light_CompoundButton_Star = 16974502; // 0x10302a6
+ field public static final int Widget_Material_Light_CompoundButton_Switch = 16974555; // 0x10302db
field public static final int Widget_Material_Light_DatePicker = 16974503; // 0x10302a7
field public static final int Widget_Material_Light_DropDownItem = 16974504; // 0x10302a8
field public static final int Widget_Material_Light_DropDownItem_Spinner = 16974505; // 0x10302a9
@@ -5759,8 +5762,8 @@
field public static final java.lang.String COMMAND_SECONDARY_TAP = "android.wallpaper.secondaryTap";
field public static final java.lang.String COMMAND_TAP = "android.wallpaper.tap";
field public static final java.lang.String EXTRA_LIVE_WALLPAPER_COMPONENT = "android.service.wallpaper.extra.LIVE_WALLPAPER_COMPONENT";
- field public static final int FLAG_SET_LOCK = 2; // 0x2
- field public static final int FLAG_SET_SYSTEM = 1; // 0x1
+ field public static final int FLAG_LOCK = 2; // 0x2
+ field public static final int FLAG_SYSTEM = 1; // 0x1
field public static final java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
}
@@ -5904,6 +5907,7 @@
method public boolean isCallerApplicationRestrictionsManagingPackage();
method public boolean isDeviceOwnerApp(java.lang.String);
method public boolean isLockTaskPermitted(java.lang.String);
+ method public boolean isManagedProfile(android.content.ComponentName);
method public boolean isMasterVolumeMuted(android.content.ComponentName);
method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public boolean isProfileOwnerApp(java.lang.String);
@@ -8526,8 +8530,9 @@
field public static final java.lang.String ACTION_LOCKED_BOOT_COMPLETED = "android.intent.action.LOCKED_BOOT_COMPLETED";
field public static final java.lang.String ACTION_MAIN = "android.intent.action.MAIN";
field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED";
- field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED = "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
+ field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABLE = "android.intent.action.MANAGED_PROFILE_AVAILABLE";
field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED";
+ field public static final java.lang.String ACTION_MANAGED_PROFILE_UNAVAILABLE = "android.intent.action.MANAGED_PROFILE_UNAVAILABLE";
field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
@@ -9925,6 +9930,7 @@
field public static final int PROTECTION_FLAG_PRE23 = 128; // 0x80
field public static final int PROTECTION_FLAG_PREINSTALLED = 1024; // 0x400
field public static final int PROTECTION_FLAG_PRIVILEGED = 16; // 0x10
+ field public static final int PROTECTION_FLAG_SETUP = 2048; // 0x800
field public static final deprecated int PROTECTION_FLAG_SYSTEM = 16; // 0x10
field public static final int PROTECTION_FLAG_VERIFIER = 512; // 0x200
field public static final int PROTECTION_MASK_BASE = 15; // 0xf
@@ -13513,6 +13519,7 @@
public final class Sensor {
method public int getFifoMaxEventCount();
method public int getFifoReservedEventCount();
+ method public int getId();
method public int getMaxDelay();
method public float getMaximumRange();
method public int getMinDelay();
@@ -13522,9 +13529,10 @@
method public float getResolution();
method public java.lang.String getStringType();
method public int getType();
- method public java.util.UUID getUuid();
method public java.lang.String getVendor();
method public int getVersion();
+ method public boolean isAdditionalInfoSupported();
+ method public boolean isDynamicSensor();
method public boolean isWakeUpSensor();
field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0
field public static final int REPORTING_MODE_ONE_SHOT = 2; // 0x2
@@ -13643,8 +13651,9 @@
method public static void getRotationMatrixFromVector(float[], float[]);
method public java.util.List<android.hardware.Sensor> getSensorList(int);
method public deprecated int getSensors();
- method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
- method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback, android.os.Handler);
+ method public boolean isDynamicSensorDiscoverySupported();
+ method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
+ method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback, android.os.Handler);
method public deprecated boolean registerListener(android.hardware.SensorListener, int);
method public deprecated boolean registerListener(android.hardware.SensorListener, int, int);
method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int);
@@ -13653,7 +13662,7 @@
method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, int, android.os.Handler);
method public static boolean remapCoordinateSystem(float[], int, int, float[]);
method public boolean requestTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
- method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
+ method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
method public deprecated void unregisterListener(android.hardware.SensorListener);
method public deprecated void unregisterListener(android.hardware.SensorListener, int);
method public void unregisterListener(android.hardware.SensorEventListener, android.hardware.Sensor);
@@ -13718,8 +13727,8 @@
field public static final float STANDARD_GRAVITY = 9.80665f;
}
- public static abstract class SensorManager.DynamicSensorConnectionCallback {
- ctor public SensorManager.DynamicSensorConnectionCallback();
+ public static abstract class SensorManager.DynamicSensorCallback {
+ ctor public SensorManager.DynamicSensorCallback();
method public void onDynamicSensorConnected(android.hardware.Sensor);
method public void onDynamicSensorDisconnected(android.hardware.Sensor);
}
@@ -19871,7 +19880,7 @@
public static abstract class AudioManager.AudioRecordingCallback {
ctor public AudioManager.AudioRecordingCallback();
- method public void onRecordConfigChanged(android.media.AudioRecordingConfiguration[]);
+ method public void onRecordingConfigChanged(android.media.AudioRecordingConfiguration[]);
}
public static abstract interface AudioManager.OnAudioFocusChangeListener {
@@ -20161,7 +20170,7 @@
field public static final int ORIENTATION_TRANSPOSE = 5; // 0x5
field public static final int ORIENTATION_TRANSVERSE = 7; // 0x7
field public static final int ORIENTATION_UNDEFINED = 0; // 0x0
- field public static final java.lang.String TAG_APERTURE = "FNumber";
+ field public static final deprecated java.lang.String TAG_APERTURE = "FNumber";
field public static final java.lang.String TAG_APERTURE_VALUE = "ApertureValue";
field public static final java.lang.String TAG_ARTIST = "Artist";
field public static final java.lang.String TAG_BITS_PER_SAMPLE = "BitsPerSample";
@@ -20232,7 +20241,7 @@
field public static final java.lang.String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
field public static final java.lang.String TAG_IMAGE_WIDTH = "ImageWidth";
field public static final java.lang.String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex";
- field public static final java.lang.String TAG_ISO = "ISOSpeedRatings";
+ field public static final deprecated java.lang.String TAG_ISO = "ISOSpeedRatings";
field public static final java.lang.String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat";
field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength";
@@ -20640,12 +20649,13 @@
field public static final int DolbyVisionLevelUhd30 = 64; // 0x40
field public static final int DolbyVisionLevelUhd48 = 128; // 0x80
field public static final int DolbyVisionLevelUhd60 = 256; // 0x100
- field public static final int DolbyVisionProfileDvavDen = 2; // 0x2
- field public static final int DolbyVisionProfileDvavDer = 1; // 0x1
- field public static final int DolbyVisionProfileDvheDen = 4; // 0x4
- field public static final int DolbyVisionProfileDvheDer = 3; // 0x3
- field public static final int DolbyVisionProfileDvheDtr = 5; // 0x5
- field public static final int DolbyVisionProfileDvheStn = 6; // 0x6
+ field public static final int DolbyVisionProfileDvavPen = 2; // 0x2
+ field public static final int DolbyVisionProfileDvavPer = 1; // 0x1
+ field public static final int DolbyVisionProfileDvheDen = 8; // 0x8
+ field public static final int DolbyVisionProfileDvheDer = 4; // 0x4
+ field public static final int DolbyVisionProfileDvheDth = 64; // 0x40
+ field public static final int DolbyVisionProfileDvheDtr = 16; // 0x10
+ field public static final int DolbyVisionProfileDvheStn = 32; // 0x20
field public static final int H263Level10 = 1; // 0x1
field public static final int H263Level20 = 2; // 0x2
field public static final int H263Level30 = 4; // 0x4
@@ -28772,6 +28782,7 @@
field public static final int TEMPERATURE_CURRENT = 0; // 0x0
field public static final int TEMPERATURE_SHUTDOWN = 2; // 0x2
field public static final int TEMPERATURE_THROTTLING = 1; // 0x1
+ field public static final int TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3; // 0x3
field public static final float UNDEFINED_TEMPERATURE = -3.4028235E38f;
}
@@ -29131,6 +29142,7 @@
method public boolean isInteractive();
method public boolean isPowerSaveMode();
method public deprecated boolean isScreenOn();
+ method public boolean isSustainedPerformanceModeSupported();
method public boolean isWakeLockLevelSupported(int);
method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
method public void reboot(java.lang.String);
@@ -29758,7 +29770,6 @@
method protected void onClick();
method protected android.view.View onCreateView(android.view.ViewGroup);
method public void onDependencyChanged(android.preference.Preference, boolean);
- method protected void onDetachedFromActivity();
method protected java.lang.Object onGetDefaultValue(android.content.res.TypedArray, int);
method public void onParentChanged(android.preference.Preference, boolean);
method protected void onPrepareForRemoval();
@@ -36794,6 +36805,7 @@
field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
+ field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
field public static final java.lang.String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
field public static final java.lang.String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
field public static final java.lang.String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
@@ -37370,7 +37382,8 @@
method public java.lang.String getDeviceSoftwareVersion();
method public java.lang.String getGroupIdLevel1();
method public java.lang.String getGroupIdLevel1(int);
- method public java.lang.String getIccSimChallengeResponse(int, java.lang.String);
+ method public java.lang.String getIccAuthentication(int, int, java.lang.String);
+ method public java.lang.String getIccAuthentication(int, int, int, java.lang.String);
method public java.lang.String getLine1AlphaTag(int);
method public java.lang.String getLine1Number();
method public java.lang.String getLine1Number(int);
@@ -37439,6 +37452,13 @@
field public static final java.lang.String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL";
field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
+ field public static final int APPTYPE_CSIM = 4; // 0x4
+ field public static final int APPTYPE_ISIM = 5; // 0x5
+ field public static final int APPTYPE_RUIM = 3; // 0x3
+ field public static final int APPTYPE_SIM = 1; // 0x1
+ field public static final int APPTYPE_USIM = 2; // 0x2
+ field public static final int AUTHTYPE_EAP_AKA = 129; // 0x81
+ field public static final int AUTHTYPE_EAP_SIM = 128; // 0x80
field public static final int CALL_STATE_IDLE = 0; // 0x0
field public static final int CALL_STATE_OFFHOOK = 2; // 0x2
field public static final int CALL_STATE_RINGING = 1; // 0x1
@@ -42338,6 +42358,7 @@
method public boolean dispatchDragEvent(android.view.DragEvent);
method protected void dispatchDraw(android.graphics.Canvas);
method public void dispatchDrawableHotspotChanged(float, float);
+ method public void dispatchFinishTemporaryDetach();
method protected boolean dispatchGenericFocusedEvent(android.view.MotionEvent);
method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
method protected boolean dispatchGenericPointerEvent(android.view.MotionEvent);
@@ -42357,6 +42378,7 @@
method protected void dispatchSetActivated(boolean);
method protected void dispatchSetPressed(boolean);
method protected void dispatchSetSelected(boolean);
+ method public void dispatchStartTemporaryDetach();
method public void dispatchSystemUiVisibilityChanged(int);
method public boolean dispatchTouchEvent(android.view.MotionEvent);
method public boolean dispatchTrackballEvent(android.view.MotionEvent);
@@ -42569,6 +42591,7 @@
method public boolean isSelected();
method public boolean isShown();
method public boolean isSoundEffectsEnabled();
+ method public final boolean isTemporarilyDetached();
method public boolean isTextAlignmentResolved();
method public boolean isTextDirectionResolved();
method public boolean isVerticalFadingEdgeEnabled();
@@ -44325,6 +44348,7 @@
public final class AccessibilityWindowInfo implements android.os.Parcelable {
method public int describeContents();
+ method public android.view.accessibility.AccessibilityNodeInfo getAnchor();
method public void getBoundsInScreen(android.graphics.Rect);
method public android.view.accessibility.AccessibilityWindowInfo getChild(int);
method public int getChildCount();
@@ -44332,6 +44356,7 @@
method public int getLayer();
method public android.view.accessibility.AccessibilityWindowInfo getParent();
method public android.view.accessibility.AccessibilityNodeInfo getRoot();
+ method public java.lang.CharSequence getTitle();
method public int getType();
method public boolean isAccessibilityFocused();
method public boolean isActive();
@@ -48335,6 +48360,7 @@
method public android.view.Menu getMenu();
method public java.lang.CharSequence getNavigationContentDescription();
method public android.graphics.drawable.Drawable getNavigationIcon();
+ method public android.view.View getNavigationView();
method public android.graphics.drawable.Drawable getOverflowIcon();
method public int getPopupTheme();
method public java.lang.CharSequence getSubtitle();
@@ -49334,9 +49360,7 @@
public final class FilePermission extends java.security.Permission implements java.io.Serializable {
ctor public FilePermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -50075,6 +50099,7 @@
method public static int compare(boolean, boolean);
method public int compareTo(java.lang.Boolean);
method public static boolean getBoolean(java.lang.String);
+ method public static int hashCode(boolean);
method public static boolean parseBoolean(java.lang.String);
method public static java.lang.String toString(boolean);
method public static java.lang.Boolean valueOf(boolean);
@@ -50092,6 +50117,7 @@
method public static java.lang.Byte decode(java.lang.String) throws java.lang.NumberFormatException;
method public double doubleValue();
method public float floatValue();
+ method public static int hashCode(byte);
method public int intValue();
method public long longValue();
method public static byte parseByte(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -50100,6 +50126,7 @@
method public static java.lang.Byte valueOf(byte);
method public static java.lang.Byte valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
method public static java.lang.Byte valueOf(java.lang.String) throws java.lang.NumberFormatException;
+ field public static final int BYTES = 1; // 0x1
field public static final byte MAX_VALUE = 127; // 0x7f
field public static final byte MIN_VALUE = -128; // 0xffffff80
field public static final int SIZE = 8; // 0x8
@@ -50137,6 +50164,7 @@
method public static int getNumericValue(int);
method public static int getType(char);
method public static int getType(int);
+ method public static int hashCode(char);
method public static char highSurrogate(int);
method public static boolean isAlphabetic(int);
method public static boolean isBmpCodePoint(int);
@@ -50197,6 +50225,7 @@
method public static char toUpperCase(char);
method public static int toUpperCase(int);
method public static java.lang.Character valueOf(char);
+ field public static final int BYTES = 2; // 0x2
field public static final byte COMBINING_SPACING_MARK = 8; // 0x8
field public static final byte CONNECTOR_PUNCTUATION = 23; // 0x17
field public static final byte CONTROL = 15; // 0xf
@@ -50823,6 +50852,7 @@
method public static int floatToIntBits(float);
method public static int floatToRawIntBits(float);
method public float floatValue();
+ method public static int hashCode(float);
method public static float intBitsToFloat(int);
method public int intValue();
method public static boolean isFinite(float);
@@ -50831,11 +50861,15 @@
method public static boolean isNaN(float);
method public boolean isNaN();
method public long longValue();
+ method public static float max(float, float);
+ method public static float min(float, float);
method public static float parseFloat(java.lang.String) throws java.lang.NumberFormatException;
+ method public static float sum(float, float);
method public static java.lang.String toHexString(float);
method public static java.lang.String toString(float);
method public static java.lang.Float valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Float valueOf(float);
+ field public static final int BYTES = 4; // 0x4
field public static final int MAX_EXPONENT = 127; // 0x7f
field public static final float MAX_VALUE = 3.4028235E38f;
field public static final int MIN_EXPONENT = -126; // 0xffffff82
@@ -51015,6 +51049,7 @@
method public static java.lang.Long valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
method public static java.lang.Long valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Long valueOf(long);
+ field public static final int BYTES = 8; // 0x8
field public static final long MAX_VALUE = 9223372036854775807L; // 0x7fffffffffffffffL
field public static final long MIN_VALUE = -9223372036854775808L; // 0x8000000000000000L
field public static final int SIZE = 64; // 0x40
@@ -51318,6 +51353,7 @@
method public static java.lang.Short decode(java.lang.String) throws java.lang.NumberFormatException;
method public double doubleValue();
method public float floatValue();
+ method public static int hashCode(short);
method public int intValue();
method public long longValue();
method public static short parseShort(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -51327,6 +51363,7 @@
method public static java.lang.Short valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
method public static java.lang.Short valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Short valueOf(short);
+ field public static final int BYTES = 2; // 0x2
field public static final short MAX_VALUE = 32767; // 0x7fff
field public static final short MIN_VALUE = -32768; // 0xffff8000
field public static final int SIZE = 16; // 0x10
@@ -52850,9 +52887,7 @@
public final class SocketPermission extends java.security.Permission implements java.io.Serializable {
ctor public SocketPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -53934,9 +53969,7 @@
public final class AllPermission extends java.security.Permission {
ctor public AllPermission();
ctor public AllPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -53950,9 +53983,7 @@
public abstract class BasicPermission extends java.security.Permission implements java.io.Serializable {
ctor public BasicPermission(java.lang.String);
ctor public BasicPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -54330,10 +54361,8 @@
public abstract class Permission implements java.security.Guard java.io.Serializable {
ctor public Permission(java.lang.String);
method public void checkGuard(java.lang.Object) throws java.lang.SecurityException;
- method public abstract boolean equals(java.lang.Object);
method public abstract java.lang.String getActions();
method public final java.lang.String getName();
- method public abstract int hashCode();
method public abstract boolean implies(java.security.Permission);
method public java.security.PermissionCollection newPermissionCollection();
}
@@ -54591,13 +54620,11 @@
public final class UnresolvedPermission extends java.security.Permission implements java.io.Serializable {
ctor public UnresolvedPermission(java.lang.String, java.lang.String, java.lang.String, java.security.cert.Certificate[]);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
method public java.lang.String getUnresolvedActions();
method public java.security.cert.Certificate[] getUnresolvedCerts();
method public java.lang.String getUnresolvedName();
method public java.lang.String getUnresolvedType();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -54655,8 +54682,6 @@
}
public abstract interface Permission {
- method public abstract boolean equals(java.lang.Object);
- method public abstract java.lang.String toString();
}
}
@@ -63965,11 +63990,9 @@
public final class PrivateCredentialPermission extends java.security.Permission {
ctor public PrivateCredentialPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
method public java.lang.String getCredentialClass();
method public java.lang.String[][] getPrincipals();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
diff --git a/api/test-removed.txt b/api/test-removed.txt
index 86085c8..3f16bca 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -94,6 +94,10 @@
package android.media.tv {
+ public final class TvInputManager {
+ method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
+ }
+
public class TvView extends android.view.ViewGroup {
method public void requestUnblockContent(android.media.tv.TvContentRating);
}
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index b208e43..0e674c8 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -88,6 +88,8 @@
runForget();
} else if ("set-emulate-fbe".equals(op)) {
runSetEmulateFbe();
+ } else if ("get-fbe-mode".equals(op)) {
+ runGetFbeMode();
} else {
throw new IllegalArgumentException();
}
@@ -145,6 +147,16 @@
StorageManager.DEBUG_EMULATE_FBE);
}
+ public void runGetFbeMode() {
+ if (StorageManager.isFileEncryptedNativeOnly()) {
+ System.out.println("native");
+ } else if (StorageManager.isFileEncryptedEmulatedOnly()) {
+ System.out.println("emulated");
+ } else {
+ System.out.println("none");
+ }
+ }
+
public void runPartition() throws RemoteException {
final String diskId = nextArg();
final String type = nextArg();
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 4019a56..ee03280 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -36,11 +36,11 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
+import com.android.internal.R;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import com.android.internal.R;
-
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
@@ -319,6 +319,9 @@
*/
public static final int FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 0x00000040;
+ /** {@hide} */
+ public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000;
+
/**
* The event types an {@link AccessibilityService} is interested in.
* <p>
@@ -687,8 +690,9 @@
}
/** {@hide} */
- public boolean isEncryptionAware() {
- return mResolveInfo.serviceInfo.directBootAware;
+ public boolean isDirectBootAware() {
+ return ((flags & FLAG_FORCE_DIRECT_BOOT_AWARE) != 0)
+ || mResolveInfo.serviceInfo.directBootAware;
}
/**
diff --git a/core/java/android/accessibilityservice/GestureDescription.java b/core/java/android/accessibilityservice/GestureDescription.java
index 7a0c89b..e18a34d 100644
--- a/core/java/android/accessibilityservice/GestureDescription.java
+++ b/core/java/android/accessibilityservice/GestureDescription.java
@@ -36,8 +36,7 @@
* Accessibility services with the
* {@link android.R.styleable#AccessibilityService_canPerformGestures} property can dispatch
* gestures. This class describes those gestures. Gestures are made up of one or more strokes.
- * Gestures are immutable; use the {@code create} methods to get common gesture, or a
- * {@code Builder} to create a new one.
+ * Gestures are immutable once built.
* <p>
* Spatial dimensions throughout are in screen pixels. Time is measured in milliseconds.
*/
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index e520b40..7465ed9 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -2798,6 +2798,15 @@
if (account == null) {
throw new IllegalArgumentException("account is null");
}
+
+ // Always include the calling package name. This just makes life easier
+ // down stream.
+ final Bundle optionsIn = new Bundle();
+ if (options != null) {
+ optionsIn.putAll(options);
+ }
+ optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
+
return new AmsTask(activity, handler, callback) {
@Override
public void doWork() throws RemoteException {
@@ -2806,7 +2815,7 @@
account,
authTokenType,
activity != null,
- options);
+ optionsIn);
}
}.start();
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index baaa55d..d1f5143 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -377,6 +377,12 @@
/** @hide Process is being cached for later use and is empty. */
public static final int PROCESS_STATE_CACHED_EMPTY = 16;
+ /** @hide The lowest process state number */
+ public static final int MIN_PROCESS_STATE = PROCESS_STATE_NONEXISTENT;
+
+ /** @hide The highest process state number */
+ public static final int MAX_PROCESS_STATE = PROCESS_STATE_CACHED_EMPTY;
+
/** @hide Should this process state be considered a background state? */
public static final boolean isProcStateBackground(int procState) {
return procState >= PROCESS_STATE_BACKUP;
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 33621852..65d48e6 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -95,7 +95,7 @@
}
return sSystemReady;
}
- static boolean sSystemReady = false;
+ static volatile boolean sSystemReady = false;
static public void broadcastStickyIntent(Intent intent, String permission, int userId) {
broadcastStickyIntent(intent, permission, AppOpsManager.OP_NONE, userId);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 5b94696..14c4fc6 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -91,6 +91,7 @@
import android.util.Slog;
import android.util.SparseIntArray;
import android.util.SuperNotCalledException;
+import android.view.ContextThemeWrapper;
import android.view.Display;
import android.view.ThreadedRenderer;
import android.view.View;
@@ -4632,7 +4633,21 @@
}
if (reportToActivity) {
- cb.onConfigurationChanged(newConfig);
+ Configuration configToReport = newConfig;
+
+ if (cb instanceof ContextThemeWrapper) {
+ // ContextThemeWrappers may override the configuration for that context.
+ // We must check and apply any overrides defined.
+ ContextThemeWrapper contextThemeWrapper = (ContextThemeWrapper) cb;
+ final Configuration localOverrideConfig =
+ contextThemeWrapper.getOverrideConfiguration();
+ if (localOverrideConfig != null) {
+ configToReport = new Configuration(newConfig);
+ configToReport.updateFrom(localOverrideConfig);
+ }
+ }
+
+ cb.onConfigurationChanged(configToReport);
}
if (activity != null) {
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index d3ca7ee..4a1aff7 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -239,9 +239,6 @@
public void onResume(Activity activity, boolean isTopOfTask) {
// After orientation change, the onResume can come in before the top Activity has
// left, so if the Activity is not top, wait a second for the top Activity to exit.
- if (mCalledExitCoordinator == null) {
- return; // This is the called activity
- }
if (isTopOfTask || mEnterTransitionCoordinator == null) {
restoreExitedViews();
restoreReenteringViews();
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index cb2130c4..e4fff9d 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -905,10 +905,12 @@
ListenerWrapper wrapper = null;
synchronized (AlarmManager.class) {
- final WeakReference<ListenerWrapper> wrapperRef;
- wrapperRef = sWrappers.get(listener);
- if (wrapperRef != null) {
- wrapper = wrapperRef.get();
+ if (sWrappers != null) {
+ final WeakReference<ListenerWrapper> wrapperRef;
+ wrapperRef = sWrappers.get(listener);
+ if (wrapperRef != null) {
+ wrapper = wrapperRef.get();
+ }
}
}
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 3a51aff..1e2cc26 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -146,6 +146,10 @@
op.removed.add(r);
}
}
+ bse.mEnterAnim = op.enterAnim;
+ bse.mExitAnim = op.exitAnim;
+ bse.mPopEnterAnim = op.popEnterAnim;
+ bse.mPopExitAnim = op.popExitAnim;
bse.addOp(op);
num++;
}
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index 83dc506..bd55a06 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -58,7 +58,7 @@
* @param context the parent context
*/
public DatePickerDialog(@NonNull Context context) {
- this(context, 0);
+ this(context, 0, null, Calendar.getInstance(), -1, -1, -1);
}
/**
@@ -70,24 +70,7 @@
* {@code context}'s default alert dialog theme
*/
public DatePickerDialog(@NonNull Context context, @StyleRes int themeResId) {
- super(context, resolveDialogTheme(context, themeResId));
-
- final Context themeContext = getContext();
- final LayoutInflater inflater = LayoutInflater.from(themeContext);
- final View view = inflater.inflate(R.layout.date_picker_dialog, null);
- setView(view);
-
- setButton(BUTTON_POSITIVE, themeContext.getString(R.string.ok), this);
- setButton(BUTTON_NEGATIVE, themeContext.getString(R.string.cancel), this);
- setButtonPanelLayoutHint(LAYOUT_HINT_SIDE);
-
- final Calendar calendar = Calendar.getInstance();
- final int year = calendar.get(Calendar.YEAR);
- final int monthOfYear = calendar.get(Calendar.MONTH);
- final int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
- mDatePicker = (DatePicker) view.findViewById(R.id.datePicker);
- mDatePicker.init(year, monthOfYear, dayOfMonth, this);
- mDatePicker.setValidationCallback(mValidationCallback);
+ this(context, themeResId, null, Calendar.getInstance(), -1, -1, -1);
}
/**
@@ -104,7 +87,7 @@
*/
public DatePickerDialog(@NonNull Context context, @Nullable OnDateSetListener listener,
int year, int month, int dayOfMonth) {
- this(context, 0, listener, year, month, dayOfMonth);
+ this(context, 0, listener, null, year, month, dayOfMonth);
}
/**
@@ -116,16 +99,40 @@
* {@code context}'s default alert dialog theme
* @param listener the listener to call when the user sets the date
* @param year the initially selected year
- * @param month the initially selected month (0-11 for compatibility with
- * {@link Calendar#MONTH})
+ * @param monthOfYear the initially selected month of the year (0-11 for
+ * compatibility with {@link Calendar#MONTH})
* @param dayOfMonth the initially selected day of month (1-31, depending
* on month)
*/
public DatePickerDialog(@NonNull Context context, @StyleRes int themeResId,
- @Nullable OnDateSetListener listener, int year, int month, int dayOfMonth) {
- this(context, themeResId);
+ @Nullable OnDateSetListener listener, int year, int monthOfYear, int dayOfMonth) {
+ this(context, themeResId, listener, null, year, monthOfYear, dayOfMonth);
+ }
- mDatePicker.updateDate(year, month, dayOfMonth);
+ private DatePickerDialog(@NonNull Context context, @StyleRes int themeResId,
+ @Nullable OnDateSetListener listener, @Nullable Calendar calendar, int year,
+ int monthOfYear, int dayOfMonth) {
+ super(context, resolveDialogTheme(context, themeResId));
+
+ final Context themeContext = getContext();
+ final LayoutInflater inflater = LayoutInflater.from(themeContext);
+ final View view = inflater.inflate(R.layout.date_picker_dialog, null);
+ setView(view);
+
+ setButton(BUTTON_POSITIVE, themeContext.getString(R.string.ok), this);
+ setButton(BUTTON_NEGATIVE, themeContext.getString(R.string.cancel), this);
+ setButtonPanelLayoutHint(LAYOUT_HINT_SIDE);
+
+ if (calendar != null) {
+ year = calendar.get(Calendar.YEAR);
+ monthOfYear = calendar.get(Calendar.MONTH);
+ dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
+ }
+
+ mDatePicker = (DatePicker) view.findViewById(R.id.datePicker);
+ mDatePicker.init(year, monthOfYear, dayOfMonth, this);
+ mDatePicker.setValidationCallback(mValidationCallback);
+
mDateSetListener = listener;
}
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 0bb1097..85a0403 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -16,6 +16,10 @@
package android.app;
+import com.android.internal.R;
+import com.android.internal.app.WindowDecorActionBar;
+import com.android.internal.policy.PhoneWindow;
+
import android.annotation.CallSuper;
import android.annotation.DrawableRes;
import android.annotation.IdRes;
@@ -43,7 +47,6 @@
import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.KeyEvent;
-import android.view.KeyboardShortcutGroup;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@@ -57,12 +60,7 @@
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
-import com.android.internal.R;
-import com.android.internal.app.WindowDecorActionBar;
-import com.android.internal.policy.PhoneWindow;
-
import java.lang.ref.WeakReference;
-import java.util.List;
/**
* Base class for Dialogs.
@@ -94,11 +92,14 @@
KeyEvent.Callback, OnCreateContextMenuListener, Window.OnWindowDismissedCallback {
private static final String TAG = "Dialog";
private Activity mOwnerActivity;
-
+
+ private final WindowManager mWindowManager;
+
final Context mContext;
- final WindowManager mWindowManager;
- Window mWindow;
+ final Window mWindow;
+
View mDecor;
+
private ActionBar mActionBar;
/**
* This field should be made private, so it is hidden from the SDK.
@@ -123,7 +124,7 @@
private static final int CANCEL = 0x44;
private static final int SHOW = 0x45;
- private Handler mListenersHandler;
+ private final Handler mListenersHandler;
private SearchEvent mSearchEvent;
@@ -131,11 +132,7 @@
private int mActionModeTypeStarting = ActionMode.TYPE_PRIMARY;
- private final Runnable mDismissAction = new Runnable() {
- public void run() {
- dismissDialog();
- }
- };
+ private final Runnable mDismissAction = this::dismissDialog;
/**
* Creates a dialog window that uses the default dialog theme.
@@ -198,14 +195,15 @@
* @hide
*/
@Deprecated
- protected Dialog(@NonNull Context context, boolean cancelable, Message cancelCallback) {
+ protected Dialog(@NonNull Context context, boolean cancelable,
+ @Nullable Message cancelCallback) {
this(context);
mCancelable = cancelable;
mCancelMessage = cancelCallback;
}
protected Dialog(@NonNull Context context, boolean cancelable,
- OnCancelListener cancelListener) {
+ @Nullable OnCancelListener cancelListener) {
this(context);
mCancelable = cancelable;
setOnCancelListener(cancelListener);
@@ -216,8 +214,7 @@
*
* @return Context The Context used by the Dialog.
*/
- @NonNull
- public final Context getContext() {
+ public final @NonNull Context getContext() {
return mContext;
}
@@ -226,7 +223,7 @@
*
* @return The ActionBar attached to the dialog or null if no ActionBar is present.
*/
- public ActionBar getActionBar() {
+ public @Nullable ActionBar getActionBar() {
return mActionBar;
}
@@ -236,7 +233,7 @@
*
* @param activity The Activity that owns this dialog.
*/
- public final void setOwnerActivity(Activity activity) {
+ public final void setOwnerActivity(@NonNull Activity activity) {
mOwnerActivity = activity;
getWindow().setVolumeControlStream(mOwnerActivity.getVolumeControlStream());
@@ -250,7 +247,7 @@
*
* @return The Activity that owns this Dialog.
*/
- public final Activity getOwnerActivity() {
+ public final @Nullable Activity getOwnerActivity() {
return mOwnerActivity;
}
@@ -316,13 +313,10 @@
l = nl;
}
- try {
- mWindowManager.addView(mDecor, l);
- mShowing = true;
-
- sendShowMessage();
- } finally {
- }
+ mWindowManager.addView(mDecor, l);
+ mShowing = true;
+
+ sendShowMessage();
}
/**
@@ -388,7 +382,7 @@
}
}
- // internal method to make sure mcreated is set properly without requiring
+ // internal method to make sure mCreated is set properly without requiring
// users to call through to super in onCreate
void dispatchOnCreate(Bundle savedInstanceState) {
if (!mCreated) {
@@ -400,7 +394,7 @@
/**
* Similar to {@link Activity#onCreate}, you should initialize your dialog
* in this method, including calling {@link #setContentView}.
- * @param savedInstanceState If this dialog is being reinitalized after a
+ * @param savedInstanceState If this dialog is being reinitialized after a
* the hosting activity was previously shut down, holds the result from
* the most recent call to {@link #onSaveInstanceState}, or null if this
* is the first time.
@@ -433,7 +427,7 @@
* state.
* @return A bundle with the state of the dialog.
*/
- public Bundle onSaveInstanceState() {
+ public @NonNull Bundle onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putBoolean(DIALOG_SHOWING_TAG, mShowing);
if (mCreated) {
@@ -452,7 +446,7 @@
* @param savedInstanceState The state of the dialog previously saved by
* {@link #onSaveInstanceState()}.
*/
- public void onRestoreInstanceState(Bundle savedInstanceState) {
+ public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
final Bundle dialogHierarchyState = savedInstanceState.getBundle(DIALOG_HIERARCHY_TAG);
if (dialogHierarchyState == null) {
// dialog has never been shown, or onCreated, nothing to restore.
@@ -473,7 +467,7 @@
* @return Window The current window, or null if the activity is not
* visual.
*/
- public Window getWindow() {
+ public @Nullable Window getWindow() {
return mWindow;
}
@@ -486,7 +480,7 @@
* @see #getWindow
* @see android.view.Window#getCurrentFocus
*/
- public View getCurrentFocus() {
+ public @Nullable View getCurrentFocus() {
return mWindow != null ? mWindow.getCurrentFocus() : null;
}
@@ -498,8 +492,7 @@
* @param id the identifier of the view to find
* @return The view with the given id or null.
*/
- @Nullable
- public View findViewById(@IdRes int id) {
+ public @Nullable View findViewById(@IdRes int id) {
return mWindow.findViewById(id);
}
@@ -520,19 +513,19 @@
*
* @param view The desired content to display.
*/
- public void setContentView(View view) {
+ public void setContentView(@NonNull View view) {
mWindow.setContentView(view);
}
/**
* Set the screen content to an explicit view. This view is placed
* directly into the screen's view hierarchy. It can itself be a complex
- * view hierarhcy.
+ * view hierarchy.
*
* @param view The desired content to display.
* @param params Layout parameters for the view.
*/
- public void setContentView(View view, ViewGroup.LayoutParams params) {
+ public void setContentView(@NonNull View view, @Nullable ViewGroup.LayoutParams params) {
mWindow.setContentView(view, params);
}
@@ -543,7 +536,7 @@
* @param view The desired content to display.
* @param params Layout parameters for the view.
*/
- public void addContentView(View view, ViewGroup.LayoutParams params) {
+ public void addContentView(@NonNull View view, @Nullable ViewGroup.LayoutParams params) {
mWindow.addContentView(view, params);
}
@@ -552,7 +545,7 @@
*
* @param title The new text to display in the title.
*/
- public void setTitle(CharSequence title) {
+ public void setTitle(@Nullable CharSequence title) {
mWindow.setTitle(title);
mWindow.getAttributes().setTitle(title);
}
@@ -578,7 +571,8 @@
* @see #onKeyUp
* @see android.view.KeyEvent
*/
- public boolean onKeyDown(int keyCode, KeyEvent event) {
+ @Override
+ public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
event.startTracking();
return true;
@@ -592,7 +586,8 @@
* KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
* the event).
*/
- public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+ @Override
+ public boolean onKeyLongPress(int keyCode, @NonNull KeyEvent event) {
return false;
}
@@ -605,7 +600,8 @@
* @see #onKeyDown
* @see KeyEvent
*/
- public boolean onKeyUp(int keyCode, KeyEvent event) {
+ @Override
+ public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
&& !event.isCanceled()) {
onBackPressed();
@@ -619,7 +615,8 @@
* KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle
* the event).
*/
- public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
+ @Override
+ public boolean onKeyMultiple(int keyCode, int repeatCount, @NonNull KeyEvent event) {
return false;
}
@@ -644,7 +641,7 @@
* @param event Description of the key event.
* @return True if the key shortcut was handled.
*/
- public boolean onKeyShortcut(int keyCode, KeyEvent event) {
+ public boolean onKeyShortcut(int keyCode, @NonNull KeyEvent event) {
return false;
}
@@ -658,7 +655,7 @@
* The default implementation will cancel the dialog when a touch
* happens outside of the window bounds.
*/
- public boolean onTouchEvent(MotionEvent event) {
+ public boolean onTouchEvent(@NonNull MotionEvent event) {
if (mCancelable && mShowing && mWindow.shouldCloseOnTouch(mContext, event)) {
cancel();
return true;
@@ -681,7 +678,7 @@
* @return Return true if you have consumed the event, false if you haven't.
* The default implementation always returns false.
*/
- public boolean onTrackballEvent(MotionEvent event) {
+ public boolean onTrackballEvent(@NonNull MotionEvent event) {
return false;
}
@@ -710,25 +707,30 @@
* @return Return true if you have consumed the event, false if you haven't.
* The default implementation always returns false.
*/
- public boolean onGenericMotionEvent(MotionEvent event) {
+ public boolean onGenericMotionEvent(@NonNull MotionEvent event) {
return false;
}
+ @Override
public void onWindowAttributesChanged(WindowManager.LayoutParams params) {
if (mDecor != null) {
mWindowManager.updateViewLayout(mDecor, params);
}
}
+ @Override
public void onContentChanged() {
}
+ @Override
public void onWindowFocusChanged(boolean hasFocus) {
}
+ @Override
public void onAttachedToWindow() {
}
+ @Override
public void onDetachedFromWindow() {
}
@@ -747,7 +749,8 @@
*
* @return boolean Return true if this event was consumed.
*/
- public boolean dispatchKeyEvent(KeyEvent event) {
+ @Override
+ public boolean dispatchKeyEvent(@NonNull KeyEvent event) {
if ((mOnKeyListener != null) && (mOnKeyListener.onKey(this, event.getKeyCode(), event))) {
return true;
}
@@ -767,7 +770,8 @@
* @param event The key shortcut event.
* @return True if this event was consumed.
*/
- public boolean dispatchKeyShortcutEvent(KeyEvent event) {
+ @Override
+ public boolean dispatchKeyShortcutEvent(@NonNull KeyEvent event) {
if (mWindow.superDispatchKeyShortcutEvent(event)) {
return true;
}
@@ -784,7 +788,8 @@
*
* @return boolean Return true if this event was consumed.
*/
- public boolean dispatchTouchEvent(MotionEvent ev) {
+ @Override
+ public boolean dispatchTouchEvent(@NonNull MotionEvent ev) {
if (mWindow.superDispatchTouchEvent(ev)) {
return true;
}
@@ -801,7 +806,8 @@
*
* @return boolean Return true if this event was consumed.
*/
- public boolean dispatchTrackballEvent(MotionEvent ev) {
+ @Override
+ public boolean dispatchTrackballEvent(@NonNull MotionEvent ev) {
if (mWindow.superDispatchTrackballEvent(ev)) {
return true;
}
@@ -818,14 +824,16 @@
*
* @return boolean Return true if this event was consumed.
*/
- public boolean dispatchGenericMotionEvent(MotionEvent ev) {
+ @Override
+ public boolean dispatchGenericMotionEvent(@NonNull MotionEvent ev) {
if (mWindow.superDispatchGenericMotionEvent(ev)) {
return true;
}
return onGenericMotionEvent(ev);
}
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+ @Override
+ public boolean dispatchPopulateAccessibilityEvent(@NonNull AccessibilityEvent event) {
event.setClassName(getClass().getName());
event.setPackageName(mContext.getPackageName());
@@ -840,6 +848,7 @@
/**
* @see Activity#onCreatePanelView(int)
*/
+ @Override
public View onCreatePanelView(int featureId) {
return null;
}
@@ -847,7 +856,8 @@
/**
* @see Activity#onCreatePanelMenu(int, Menu)
*/
- public boolean onCreatePanelMenu(int featureId, Menu menu) {
+ @Override
+ public boolean onCreatePanelMenu(int featureId, @NonNull Menu menu) {
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
return onCreateOptionsMenu(menu);
}
@@ -858,10 +868,10 @@
/**
* @see Activity#onPreparePanel(int, View, Menu)
*/
+ @Override
public boolean onPreparePanel(int featureId, View view, Menu menu) {
if (featureId == Window.FEATURE_OPTIONS_PANEL && menu != null) {
- boolean goforit = onPrepareOptionsMenu(menu);
- return goforit && menu.hasVisibleItems();
+ return onPrepareOptionsMenu(menu) && menu.hasVisibleItems();
}
return true;
}
@@ -869,6 +879,7 @@
/**
* @see Activity#onMenuOpened(int, Menu)
*/
+ @Override
public boolean onMenuOpened(int featureId, Menu menu) {
if (featureId == Window.FEATURE_ACTION_BAR) {
mActionBar.dispatchMenuVisibilityChanged(true);
@@ -879,6 +890,7 @@
/**
* @see Activity#onMenuItemSelected(int, MenuItem)
*/
+ @Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
return false;
}
@@ -886,6 +898,7 @@
/**
* @see Activity#onPanelClosed(int, Menu)
*/
+ @Override
public void onPanelClosed(int featureId, Menu menu) {
if (featureId == Window.FEATURE_ACTION_BAR) {
mActionBar.dispatchMenuVisibilityChanged(false);
@@ -900,7 +913,7 @@
* @see Activity#onCreateOptionsMenu(Menu)
* @see #getOwnerActivity()
*/
- public boolean onCreateOptionsMenu(Menu menu) {
+ public boolean onCreateOptionsMenu(@NonNull Menu menu) {
return true;
}
@@ -912,21 +925,21 @@
* @see Activity#onPrepareOptionsMenu(Menu)
* @see #getOwnerActivity()
*/
- public boolean onPrepareOptionsMenu(Menu menu) {
+ public boolean onPrepareOptionsMenu(@NonNull Menu menu) {
return true;
}
/**
* @see Activity#onOptionsItemSelected(MenuItem)
*/
- public boolean onOptionsItemSelected(MenuItem item) {
+ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
return false;
}
/**
* @see Activity#onOptionsMenuClosed(Menu)
*/
- public void onOptionsMenuClosed(Menu menu) {
+ public void onOptionsMenuClosed(@NonNull Menu menu) {
}
/**
@@ -959,47 +972,49 @@
/**
* @see Activity#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)
*/
+ @Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
}
/**
* @see Activity#registerForContextMenu(View)
*/
- public void registerForContextMenu(View view) {
+ public void registerForContextMenu(@NonNull View view) {
view.setOnCreateContextMenuListener(this);
}
/**
* @see Activity#unregisterForContextMenu(View)
*/
- public void unregisterForContextMenu(View view) {
+ public void unregisterForContextMenu(@NonNull View view) {
view.setOnCreateContextMenuListener(null);
}
/**
* @see Activity#openContextMenu(View)
*/
- public void openContextMenu(View view) {
+ public void openContextMenu(@NonNull View view) {
view.showContextMenu();
}
/**
* @see Activity#onContextItemSelected(MenuItem)
*/
- public boolean onContextItemSelected(MenuItem item) {
+ public boolean onContextItemSelected(@NonNull MenuItem item) {
return false;
}
/**
* @see Activity#onContextMenuClosed(Menu)
*/
- public void onContextMenuClosed(Menu menu) {
+ public void onContextMenuClosed(@NonNull Menu menu) {
}
/**
* This hook is called when the user signals the desire to start a search.
*/
- public boolean onSearchRequested(SearchEvent searchEvent) {
+ @Override
+ public boolean onSearchRequested(@NonNull SearchEvent searchEvent) {
mSearchEvent = searchEvent;
return onSearchRequested();
}
@@ -1007,6 +1022,7 @@
/**
* This hook is called when the user signals the desire to start a search.
*/
+ @Override
public boolean onSearchRequested() {
final SearchManager searchManager = (SearchManager) mContext
.getSystemService(Context.SEARCH_SERVICE);
@@ -1029,13 +1045,10 @@
* @return SearchEvent The SearchEvent that triggered the {@link
* #onSearchRequested} callback.
*/
- public final SearchEvent getSearchEvent() {
+ public final @Nullable SearchEvent getSearchEvent() {
return mSearchEvent;
}
- /**
- * {@inheritDoc}
- */
@Override
public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
if (mActionBar != null && mActionModeTypeStarting == ActionMode.TYPE_PRIMARY) {
@@ -1044,9 +1057,6 @@
return null;
}
- /**
- * {@inheritDoc}
- */
@Override
public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type) {
try {
@@ -1063,6 +1073,7 @@
* Note that if you override this method you should always call through
* to the superclass implementation by calling super.onActionModeStarted(mode).
*/
+ @Override
@CallSuper
public void onActionModeStarted(ActionMode mode) {
mActionMode = mode;
@@ -1074,6 +1085,7 @@
* Note that if you override this method you should always call through
* to the superclass implementation by calling super.onActionModeFinished(mode).
*/
+ @Override
@CallSuper
public void onActionModeFinished(ActionMode mode) {
if (mode == mActionMode) {
@@ -1139,7 +1151,7 @@
* Convenience for calling
* {@link android.view.Window#setFeatureDrawableUri}.
*/
- public final void setFeatureDrawableUri(int featureId, Uri uri) {
+ public final void setFeatureDrawableUri(int featureId, @Nullable Uri uri) {
getWindow().setFeatureDrawableUri(featureId, uri);
}
@@ -1147,7 +1159,7 @@
* Convenience for calling
* {@link android.view.Window#setFeatureDrawable(int, Drawable)}.
*/
- public final void setFeatureDrawable(int featureId, Drawable drawable) {
+ public final void setFeatureDrawable(int featureId, @Nullable Drawable drawable) {
getWindow().setFeatureDrawable(featureId, drawable);
}
@@ -1159,7 +1171,7 @@
getWindow().setFeatureDrawableAlpha(featureId, alpha);
}
- public LayoutInflater getLayoutInflater() {
+ public @NonNull LayoutInflater getLayoutInflater() {
return getWindow().getLayoutInflater();
}
@@ -1191,6 +1203,7 @@
* Cancel the dialog. This is essentially the same as calling {@link #dismiss()}, but it will
* also call your {@link DialogInterface.OnCancelListener} (if registered).
*/
+ @Override
public void cancel() {
if (!mCanceled && mCancelMessage != null) {
mCanceled = true;
@@ -1211,7 +1224,7 @@
*
* @param listener The {@link DialogInterface.OnCancelListener} to use.
*/
- public void setOnCancelListener(final OnCancelListener listener) {
+ public void setOnCancelListener(@Nullable OnCancelListener listener) {
if (mCancelAndDismissTaken != null) {
throw new IllegalStateException(
"OnCancelListener is already taken by "
@@ -1229,7 +1242,7 @@
* @param msg The msg to send when the dialog is canceled.
* @see #setOnCancelListener(android.content.DialogInterface.OnCancelListener)
*/
- public void setCancelMessage(final Message msg) {
+ public void setCancelMessage(@Nullable Message msg) {
mCancelMessage = msg;
}
@@ -1237,7 +1250,7 @@
* Set a listener to be invoked when the dialog is dismissed.
* @param listener The {@link DialogInterface.OnDismissListener} to use.
*/
- public void setOnDismissListener(final OnDismissListener listener) {
+ public void setOnDismissListener(@Nullable OnDismissListener listener) {
if (mCancelAndDismissTaken != null) {
throw new IllegalStateException(
"OnDismissListener is already taken by "
@@ -1254,7 +1267,7 @@
* Sets a listener to be invoked when the dialog is shown.
* @param listener The {@link DialogInterface.OnShowListener} to use.
*/
- public void setOnShowListener(OnShowListener listener) {
+ public void setOnShowListener(@Nullable OnShowListener listener) {
if (listener != null) {
mShowMessage = mListenersHandler.obtainMessage(SHOW, listener);
} else {
@@ -1266,13 +1279,13 @@
* Set a message to be sent when the dialog is dismissed.
* @param msg The msg to send when the dialog is dismissed.
*/
- public void setDismissMessage(final Message msg) {
+ public void setDismissMessage(@Nullable Message msg) {
mDismissMessage = msg;
}
/** @hide */
- public boolean takeCancelAndDismissListeners(String msg, final OnCancelListener cancel,
- final OnDismissListener dismiss) {
+ public boolean takeCancelAndDismissListeners(@Nullable String msg,
+ @Nullable OnCancelListener cancel, @Nullable OnDismissListener dismiss) {
if (mCancelAndDismissTaken != null) {
mCancelAndDismissTaken = null;
} else if (mCancelMessage != null || mDismissMessage != null) {
@@ -1306,15 +1319,15 @@
/**
* Sets the callback that will be called if a key is dispatched to the dialog.
*/
- public void setOnKeyListener(final OnKeyListener onKeyListener) {
+ public void setOnKeyListener(@Nullable OnKeyListener onKeyListener) {
mOnKeyListener = onKeyListener;
}
private static final class ListenersHandler extends Handler {
- private WeakReference<DialogInterface> mDialog;
+ private final WeakReference<DialogInterface> mDialog;
public ListenersHandler(Dialog dialog) {
- mDialog = new WeakReference<DialogInterface>(dialog);
+ mDialog = new WeakReference<>(dialog);
}
@Override
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index bb3c719..c745644 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -1033,11 +1033,11 @@
* false if it is not.
*/
public void setUserVisibleHint(boolean isVisibleToUser) {
- if (!mUserVisibleHint && isVisibleToUser && mState < STARTED && mFragmentManager != null) {
+ if (!mUserVisibleHint && isVisibleToUser && mState < STARTED && isAdded()) {
mFragmentManager.performPendingDeferredStart(this);
}
mUserVisibleHint = isVisibleToUser;
- mDeferStart = !isVisibleToUser;
+ mDeferStart = mState < STARTED && !isVisibleToUser;
}
/**
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 3f22385..4c4f128 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -440,6 +440,11 @@
compatInfo);
classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
+ if (DEBUG) {
+ Slog.d(TAG, "createBaseActivityResources activity=" + activityToken
+ + " with key=" + key);
+ }
+
synchronized (this) {
final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
activityToken);
@@ -651,6 +656,16 @@
activityResources.overrideConfig.setToDefaults();
}
+ if (DEBUG) {
+ Throwable here = new Throwable();
+ here.fillInStackTrace();
+ Slog.d(TAG, "updating resources override for activity=" + activityToken
+ + " from oldConfig=" + Configuration.resourceQualifierString(oldConfig)
+ + " to newConfig="
+ + Configuration.resourceQualifierString(activityResources.overrideConfig),
+ here);
+ }
+
final boolean activityHasOverrideConfig =
!activityResources.overrideConfig.equals(Configuration.EMPTY);
@@ -692,9 +707,15 @@
oldKey.mOverlayDirs, oldKey.mLibDirs, oldKey.mDisplayId,
rebasedOverrideConfig, oldKey.mCompatInfo);
+ if (DEBUG) {
+ Slog.d(TAG, "rebasing ref=" + resources + " from oldKey=" + oldKey
+ + " to newKey=" + newKey);
+ }
+
ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(newKey);
if (resourcesImpl == null) {
resourcesImpl = createResourcesImpl(newKey);
+ mResourceImpls.put(newKey, new WeakReference<>(resourcesImpl));
}
if (resourcesImpl != resources.getImpl()) {
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 276f774..2c1ee8e 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -36,6 +36,7 @@
import android.view.WindowContentFrameStats;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.IAccessibilityManager;
+
import libcore.io.IoUtils;
import java.io.FileOutputStream;
@@ -77,6 +78,7 @@
private int mOwningUid;
+ @Override
public void connect(IAccessibilityServiceClient client, int flags) {
if (client == null) {
throw new IllegalArgumentException("Client cannot be null!");
@@ -326,11 +328,12 @@
int flags) {
IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
- AccessibilityServiceInfo info = new AccessibilityServiceInfo();
+ final AccessibilityServiceInfo info = new AccessibilityServiceInfo();
info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
- | AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS;
+ | AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS
+ | AccessibilityServiceInfo.FLAG_FORCE_DIRECT_BOOT_AWARE;
info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
| AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
| AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index b52af27..72b9318 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -161,8 +161,8 @@
/** @hide */
@IntDef(flag = true, value = {
- FLAG_SET_SYSTEM,
- FLAG_SET_LOCK
+ FLAG_SYSTEM,
+ FLAG_LOCK
})
@Retention(RetentionPolicy.SOURCE)
public @interface SetWallpaperFlags {}
@@ -170,12 +170,12 @@
/**
* Flag: use the supplied imagery as the general system wallpaper.
*/
- public static final int FLAG_SET_SYSTEM = 1 << 0;
+ public static final int FLAG_SYSTEM = 1 << 0;
/**
* Flag: use the supplied imagery as the lock-screen wallpaper.
*/
- public static final int FLAG_SET_LOCK = 1 << 1;
+ public static final int FLAG_LOCK = 1 << 1;
private final Context mContext;
@@ -336,7 +336,7 @@
try {
Bundle params = new Bundle();
- ParcelFileDescriptor fd = mService.getWallpaper(this, FLAG_SET_SYSTEM,
+ ParcelFileDescriptor fd = mService.getWallpaper(this, FLAG_SYSTEM,
params, userId);
if (fd != null) {
try {
@@ -663,11 +663,18 @@
/**
* Get an open, readable file descriptor to the given wallpaper image file.
- * The callee is resopnsible for closing the fd when done ingesting the file.
+ * The caller is responsible for closing the file descriptor when done ingesting the file.
*
* <p>If no lock-specific wallpaper has been configured for the given user, then
- * this method will return {@code null} when requesting {@link #FLAG_SET_LOCK} rather than
+ * this method will return {@code null} when requesting {@link #FLAG_LOCK} rather than
* returning the system wallpaper's image file.
+ *
+ * @param which The wallpaper whose image file is to be retrieved. Must be a single
+ * defined kind of wallpaper, either {@link #FLAG_SYSTEM} or
+ * {@link #FLAG_LOCK}.
+ *
+ * @see #FLAG_LOCK
+ * @see #FLAG_SYSTEM
*/
public ParcelFileDescriptor getWallpaperFile(int which) {
return getWallpaperFile(which, mContext.getUserId());
@@ -677,10 +684,19 @@
* Version of {@link #getWallpaperFile(int)} that can access the wallpaper data
* for a given user. The caller must hold the INTERACT_ACROSS_USERS_FULL
* permission to access another user's wallpaper data.
+ *
+ * @param which The wallpaper whose image file is to be retrieved. Must be a single
+ * defined kind of wallpaper, either {@link #FLAG_SYSTEM} or
+ * {@link #FLAG_LOCK}.
+ * @param userId The user or profile whose imagery is to be retrieved
+ *
+ * @see #FLAG_LOCK
+ * @see #FLAG_SYSTEM
+ *
* @hide
*/
public ParcelFileDescriptor getWallpaperFile(int which, int userId) {
- if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) {
+ if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
throw new IllegalArgumentException("Must request exactly one kind of wallpaper");
}
@@ -730,8 +746,8 @@
* such wallpaper configured, returns a negative number.
*
* @param which The wallpaper whose ID is to be returned. Must be a single
- * defined kind of wallpaper, either {@link #FLAG_SET_SYSTEM} or
- * {@link #FLAG_SET_LOCK}.
+ * defined kind of wallpaper, either {@link #FLAG_SYSTEM} or
+ * {@link #FLAG_LOCK}.
* @return The positive numeric ID of the current wallpaper of the given kind,
* or a negative value if no such wallpaper is configured.
*/
@@ -823,24 +839,24 @@
* <p>This method requires the caller to hold the permission
* {@link android.Manifest.permission#SET_WALLPAPER}.
*
- * @param resid The bitmap to save.
+ * @param resid The resource ID of the bitmap to be used as the wallpaper image
*
* @throws IOException If an error occurs reverting to the built-in
* wallpaper.
*/
public void setResource(@RawRes int resid) throws IOException {
- setResource(resid, FLAG_SET_SYSTEM);
+ setResource(resid, FLAG_SYSTEM);
}
/**
- * Version of {@link #setResource(int)} that takes an optional Bundle for returning
- * metadata about the operation to the caller.
+ * Version of {@link #setResource(int)} that allows the caller to specify which
+ * of the supported wallpaper categories to set.
*
- * @param resid
- * @param which Flags indicating which wallpaper(s) to configure with the new imagery.
+ * @param resid The resource ID of the bitmap to be used as the wallpaper image
+ * @param which Flags indicating which wallpaper(s) to configure with the new imagery
*
- * @see #FLAG_SET_LOCK
- * @see #FLAG_SET_SYSTEM
+ * @see #FLAG_LOCK
+ * @see #FLAG_SYSTEM
*
* @return An integer ID assigned to the newly active wallpaper; or zero on failure.
*
@@ -934,11 +950,10 @@
*/
public int setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup)
throws IOException {
- return setBitmap(fullImage, visibleCropHint, allowBackup, FLAG_SET_SYSTEM);
+ return setBitmap(fullImage, visibleCropHint, allowBackup, FLAG_SYSTEM);
}
/**
- /**
* Version of {@link #setBitmap(Bitmap, Rect, boolean)} that allows the caller
* to specify which of the supported wallpaper categories to set.
*
@@ -951,8 +966,8 @@
* image for restore to a future device; {@code false} otherwise.
* @param which Flags indicating which wallpaper(s) to configure with the new imagery.
*
- * @see #FLAG_SET_LOCK
- * @see #FLAG_SET_SYSTEM
+ * @see #FLAG_LOCK
+ * @see #FLAG_SYSTEM
*
* @return An integer ID assigned to the newly active wallpaper; or zero on failure.
*
@@ -1054,7 +1069,7 @@
*/
public int setStream(InputStream bitmapData, Rect visibleCropHint, boolean allowBackup)
throws IOException {
- return setStream(bitmapData, visibleCropHint, allowBackup, FLAG_SET_SYSTEM);
+ return setStream(bitmapData, visibleCropHint, allowBackup, FLAG_SYSTEM);
}
/**
@@ -1070,8 +1085,8 @@
* image for restore to a future device; {@code false} otherwise.
* @param which Flags indicating which wallpaper(s) to configure with the new imagery.
*
- * @see #FLAG_SET_LOCK
- * @see #FLAG_SET_SYSTEM
+ * @see #FLAG_LOCK
+ * @see #FLAG_SYSTEM
*
* @throws IOException
*/
@@ -1287,7 +1302,7 @@
*/
@SystemApi
public void clearWallpaper() {
- clearWallpaper(FLAG_SET_SYSTEM, mContext.getUserId());
+ clearWallpaper(FLAG_SYSTEM, mContext.getUserId());
}
/**
@@ -1467,20 +1482,20 @@
/**
* Remove one or more currently set wallpapers, reverting to the system default
- * display for each one. If {@link #FLAG_SET_SYSTEM} is set in the {@code which}
+ * display for each one. If {@link #FLAG_SYSTEM} is set in the {@code which}
* parameter, the intent {@link Intent#ACTION_WALLPAPER_CHANGED} will be broadcast
* upon success.
*
- * @param which A bitwise combination of {@link #FLAG_SET_SYSTEM} or
- * {@link #FLAG_SET_LOCK}
+ * @param which A bitwise combination of {@link #FLAG_SYSTEM} or
+ * {@link #FLAG_LOCK}
* @throws IOException If an error occurs reverting to the built-in wallpaper.
*/
public void clear(int which) throws IOException {
- if ((which & FLAG_SET_SYSTEM) != 0) {
+ if ((which & FLAG_SYSTEM) != 0) {
clear();
}
- if ((which & FLAG_SET_LOCK) != 0) {
- clearWallpaper(FLAG_SET_LOCK, mContext.getUserId());
+ if ((which & FLAG_LOCK) != 0) {
+ clearWallpaper(FLAG_LOCK, mContext.getUserId());
}
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index c9b1d0c..b924327 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2185,9 +2185,6 @@
* Force a new device unlock password (the password needed to access the entire device, not for
* individual accounts) on the user. This takes effect immediately.
* <p>
- * Calling this from a managed profile that shares the password with the owner profile will
- * throw a security exception.
- * <p>
* <em>Note: This API has been limited as of {@link android.os.Build.VERSION_CODES#N} for
* device admins that are not device owner and not profile owner.
* The password can now only be changed if there is currently no password set. Device owner
@@ -2201,10 +2198,10 @@
* case the currently active quality will be increased to match.
* <p>
* Calling with a null or empty password will clear any existing PIN, pattern or password if the
- * current password constraints allow it. <em>Note: This will not
- * work in {@link android.os.Build.VERSION_CODES#N} and later for device admins that are not
- * device owner and not profile owner. Once set, the password cannot be changed to null or
- * empty, except by device owner or profile owner.</em>
+ * current password constraints allow it. <em>Note: This will not work in
+ * {@link android.os.Build.VERSION_CODES#N} and later for managed profiles, or for device admins
+ * that are not device owner or profile owner. Once set, the password cannot be changed to null
+ * or empty except by these admins.</em>
* <p>
* The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD} to be able to call this method; if it has
@@ -2655,6 +2652,43 @@
}
/**
+ * Mark a CA certificate as approved by the device user. This means that they have been notified
+ * of the installation, were made aware of the risks, viewed the certificate and still wanted to
+ * keep the certificate on the device.
+ *
+ * Calling with {@param approval} as {@code true} will cancel any ongoing warnings related to
+ * this certificate.
+ *
+ * @hide
+ */
+ public boolean approveCaCert(String alias, int userHandle, boolean approval) {
+ if (mService != null) {
+ try {
+ return mService.approveCaCert(alias, userHandle, approval);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check whether a CA certificate has been approved by the device user.
+ *
+ * @hide
+ */
+ public boolean isCaCertApproved(String alias, int userHandle) {
+ if (mService != null) {
+ try {
+ return mService.isCaCertApproved(alias, userHandle);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return false;
+ }
+
+ /**
* Installs the given certificate as a user CA.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
@@ -5617,10 +5651,9 @@
}
/**
- * @hide
* Return if this user is a managed profile of another user. An admin can become the profile
* owner of a managed profile with {@link #ACTION_PROVISION_MANAGED_PROFILE} and of a managed
- * user with {@link #ACTION_PROVISION_MANAGED_USER}.
+ * user with {@link #createAndManageUser}
* @param admin Which profile owner this request is associated with.
* @return if this user is a managed profile of another user.
*/
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 8fa4c3a..6ee56aa 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -144,6 +144,8 @@
boolean installCaCert(in ComponentName admin, in byte[] certBuffer);
void uninstallCaCerts(in ComponentName admin, in String[] aliases);
void enforceCanManageCaCerts(in ComponentName admin);
+ boolean approveCaCert(in String alias, int userHandle, boolean approval);
+ boolean isCaCertApproved(in String alias, int userHandle);
boolean installKeyPair(in ComponentName who, in byte[] privKeyBuffer, in byte[] certBuffer,
in byte[] certChainBuffer, String alias, boolean requestAccess);
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index 1af4953..2d9f4a7 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -17,8 +17,7 @@
package android.appwidget;
import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.List;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -35,7 +34,9 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemClock;
import android.util.DisplayMetrics;
+import android.util.SparseArray;
import android.util.TypedValue;
import android.widget.RemoteViews;
import android.widget.RemoteViews.OnClickHandler;
@@ -62,7 +63,7 @@
private final Handler mHandler;
private final int mHostId;
private final Callbacks mCallbacks;
- private final HashMap<Integer,AppWidgetHostView> mViews = new HashMap<>();
+ private final SparseArray<AppWidgetHostView> mViews = new SparseArray<>();
private OnClickHandler mOnClickHandler;
static class Callbacks extends IAppWidgetHost.Stub {
@@ -164,7 +165,6 @@
bindService();
}
-
private static void bindService() {
synchronized (sServiceLock) {
if (sService == null) {
@@ -179,17 +179,25 @@
* becomes visible, i.e. from onStart() in your Activity.
*/
public void startListening() {
- int[] updatedIds;
- ArrayList<RemoteViews> updatedViews = new ArrayList<RemoteViews>();
+ final int[] idsToUpdate;
+ synchronized (mViews) {
+ int N = mViews.size();
+ idsToUpdate = new int[N];
+ for (int i = 0; i < N; i++) {
+ idsToUpdate[i] = mViews.keyAt(i);
+ }
+ }
+ List<RemoteViews> updatedViews;
+ int[] updatedIds = new int[idsToUpdate.length];
try {
- updatedIds = sService.startListening(mCallbacks, mContextOpPackageName, mHostId,
- updatedViews);
+ updatedViews = sService.startListening(
+ mCallbacks, mContextOpPackageName, mHostId, idsToUpdate, updatedIds).getList();
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
- final int N = updatedIds.length;
+ int N = updatedViews.size();
for (int i = 0; i < N; i++) {
updateAppWidgetView(updatedIds[i], updatedViews.get(i));
}
@@ -206,10 +214,6 @@
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
-
- // This is here because keyguard needs it since it'll be switching users after this call.
- // If it turns out other apps need to call this often, we should re-think how this works.
- clearViews();
}
/**
@@ -418,7 +422,9 @@
* Clear the list of Views that have been created by this AppWidgetHost.
*/
protected void clearViews() {
- mViews.clear();
+ synchronized (mViews) {
+ mViews.clear();
+ }
}
}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index d762a17..2a7eff8 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -36,6 +36,7 @@
import android.os.ParcelUuid;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.util.Log;
import android.util.Pair;
@@ -1015,6 +1016,8 @@
try {
if (mService != null) {
return mService.factoryReset();
+ } else {
+ SystemProperties.set("persist.bluetooth.factoryreset", "true");
}
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
diff --git a/core/java/android/bluetooth/BluetoothGattCharacteristic.java b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
index 7d698b3..01f82e6 100644
--- a/core/java/android/bluetooth/BluetoothGattCharacteristic.java
+++ b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
@@ -284,6 +284,8 @@
out.writeInt(mInstance);
out.writeInt(mProperties);
out.writeInt(mPermissions);
+ out.writeInt(mKeySize);
+ out.writeInt(mWriteType);
out.writeTypedList(mDescriptors);
}
@@ -303,6 +305,8 @@
mInstance = in.readInt();
mProperties = in.readInt();
mPermissions = in.readInt();
+ mKeySize = in.readInt();
+ mWriteType = in.readInt();
mDescriptors = new ArrayList<BluetoothGattDescriptor>();
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index e355a1c..35437a1 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -144,7 +144,7 @@
}
/**
- *
+ *
* Get a list of devices that match any of the given connection
* states.
*
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 10259be..30f2c94 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3056,15 +3056,29 @@
public static final String ACTION_MANAGED_PROFILE_UNLOCKED =
"android.intent.action.MANAGED_PROFILE_UNLOCKED";
+ /** @hide */
+ public static final String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED =
+ "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
+
/**
- * Broadcast sent to the primary user when an associated managed profile's availability has
- * changed. This includes when the user toggles the profile's quiet mode. Carries an extra
+ * Broadcast sent to the primary user when an associated managed profile has become available.
+ * Currently this includes when the user disables quiet mode for the profile. Carries an extra
* {@link #EXTRA_USER} that specifies the UserHandle of the profile. When quiet mode is changed,
* this broadcast will carry a boolean extra {@link #EXTRA_QUIET_MODE} indicating the new state
* of quiet mode. This is only sent to registered receivers, not manifest receivers.
*/
- public static final String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED =
- "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
+ public static final String ACTION_MANAGED_PROFILE_AVAILABLE =
+ "android.intent.action.MANAGED_PROFILE_AVAILABLE";
+
+ /**
+ * Broadcast sent to the primary user when an associated managed profile has become unavailable.
+ * Currently this includes when the user enables quiet mode for the profile. Carries an extra
+ * {@link #EXTRA_USER} that specifies the UserHandle of the profile. When quiet mode is changed,
+ * this broadcast will carry a boolean extra {@link #EXTRA_QUIET_MODE} indicating the new state
+ * of quiet mode. This is only sent to registered receivers, not manifest receivers.
+ */
+ public static final String ACTION_MANAGED_PROFILE_UNAVAILABLE =
+ "android.intent.action.MANAGED_PROFILE_UNAVAILABLE";
/**
* Sent when the user taps on the clock widget in the system's "quick settings" area.
@@ -4165,6 +4179,9 @@
/**
* Optional boolean extra indicating whether quiet mode has been switched on or off.
+ * When a profile goes into quiet mode, all apps in the profile are killed and the
+ * profile user is stopped. Widgets originating from the profile are masked, and app
+ * launcher icons are grayed out.
*/
public static final String EXTRA_QUIET_MODE = "android.intent.extra.QUIET_MODE";
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 3a17e23..ed5dfa5 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -883,6 +883,15 @@
return true;
}
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof AuthorityEntry) {
+ final AuthorityEntry other = (AuthorityEntry)obj;
+ return match(other);
+ }
+ return false;
+ }
+
/**
* Determine whether this AuthorityEntry matches the given data Uri.
* <em>Note that this comparison is case-sensitive, unlike formal
@@ -917,7 +926,7 @@
}
return MATCH_CATEGORY_HOST;
}
- };
+ }
/**
* Add a new Intent data "scheme specific part" to match against. The filter must
diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java
index a5617b4..40e1a9f 100644
--- a/core/java/android/content/pm/LauncherActivityInfo.java
+++ b/core/java/android/content/pm/LauncherActivityInfo.java
@@ -103,53 +103,22 @@
* @return The drawable associated with the activity.
*/
public Drawable getIcon(int density) {
- final int iconRes = mResolveInfo.getIconResource();
- Drawable icon = getDrawableForDensity(iconRes, density);
- // Get the default density icon
- if (icon == null) {
- icon = mResolveInfo.loadIcon(mPm);
- }
- return icon;
- }
-
- /**
- * Returns the icon for this activity, without any badging for the profile.
- * This function can get the icon no matter the icon needs to be badged or not.
- * @param density The preferred density of the icon, zero for default density. Use
- * density DPI values from {@link DisplayMetrics}.
- * @see #getBadgedIcon(int)
- * @see DisplayMetrics
- * @return The drawable associated with the activity.
- */
- private Drawable getOriginalIcon(int density) {
final int iconRes = mResolveInfo.getIconResourceInternal();
- Drawable icon = getDrawableForDensity(iconRes, density);
- // Get the default density icon
- if (icon == null) {
- icon = mResolveInfo.loadIcon(mPm);
- }
- return icon;
- }
-
- /**
- * Returns the drawable for this activity, without any badging for the profile.
- * @param iconRes id of the drawable.
- * @param density The preferred density of the icon, zero for default density. Use
- * density DPI values from {@link DisplayMetrics}.
- * @see DisplayMetrics
- * @return The drawable associated with the resource id.
- */
- private Drawable getDrawableForDensity(int iconRes, int density) {
+ Drawable icon = null;
// Get the preferred density icon from the app's resources
if (density != 0 && iconRes != 0) {
try {
final Resources resources
= mPm.getResourcesForApplication(mActivityInfo.applicationInfo);
- return resources.getDrawableForDensity(iconRes, density);
+ icon = resources.getDrawableForDensity(iconRes, density);
} catch (NameNotFoundException | Resources.NotFoundException exc) {
}
}
- return null;
+ // Get the default density icon
+ if (icon == null) {
+ icon = mResolveInfo.loadIcon(mPm);
+ }
+ return icon;
}
/**
@@ -201,7 +170,7 @@
* @return A badged icon for the activity.
*/
public Drawable getBadgedIcon(int density) {
- Drawable originalIcon = getOriginalIcon(density);
+ Drawable originalIcon = getIcon(density);
if (originalIcon instanceof BitmapDrawable) {
return mPm.getUserBadgedIcon(originalIcon, mUser);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e89cbd7..39bc783 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -130,6 +130,7 @@
MATCH_DISABLED_COMPONENTS,
MATCH_DISABLED_UNTIL_USED_COMPONENTS,
MATCH_SYSTEM_ONLY,
+ MATCH_FACTORY_ONLY,
MATCH_DEBUG_TRIAGED_MISSING,
})
@Retention(RetentionPolicy.SOURCE)
@@ -415,6 +416,13 @@
public static final int MATCH_SYSTEM_ONLY = 0x00100000;
/**
+ * Internal {@link PackageInfo} flag: include only components on the system image.
+ * This will not return information on any unbundled update to system components.
+ * @hide
+ */
+ public static final int MATCH_FACTORY_ONLY = 0x00200000;
+
+ /**
* Internal flag used to indicate that a system component has done their
* homework and verified that they correctly handle packages and components
* that come and go over time. In particular:
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 984a960..65e0b92 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -113,6 +113,13 @@
public static final int PROTECTION_FLAG_PREINSTALLED = 0x400;
/**
+ * Additional flag for {@link #protectionLevel}, corresponding
+ * to the <code>setup</code> value of
+ * {@link android.R.attr#protectionLevel}.
+ */
+ public static final int PROTECTION_FLAG_SETUP = 0x800;
+
+ /**
* Mask for {@link #protectionLevel}: the basic protection type.
*/
public static final int PROTECTION_MASK_BASE = 0xf;
@@ -226,6 +233,9 @@
if ((level&PermissionInfo.PROTECTION_FLAG_PREINSTALLED) != 0) {
protLevel += "|preinstalled";
}
+ if ((level&PermissionInfo.PROTECTION_FLAG_SETUP) != 0) {
+ protLevel += "|setup";
+ }
return protLevel;
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 387fda7..93fe73b 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -714,12 +714,11 @@
* the resource ID passed here is an alias to another Drawable resource.
* This means that if the density configuration of the alias resource
* is different than the actual resource, the density of the returned
- * Drawable would be incorrect, resulting in bad scaling. To work
- * around this, you can instead retrieve the Drawable through
- * {@link TypedArray#getDrawable TypedArray.getDrawable}. Use
- * {@link android.content.Context#obtainStyledAttributes(int[])
- * Context.obtainStyledAttributes} with
- * an array containing the resource ID of interest to create the TypedArray.</p>
+ * Drawable would be incorrect, resulting in bad scaling. To work
+ * around this, you can instead manually resolve the aliased reference
+ * by using {@link #getValue(int, TypedValue, boolean)} and passing
+ * {@code true} for {@code resolveRefs}. The resulting
+ * {@link TypedValue#resourceId} value may be passed to this method.</p>
*
* <p class="note"><strong>Note:</strong> To obtain a themed drawable, use
* {@link android.content.Context#getDrawable(int) Context.getDrawable(int)}
diff --git a/core/java/android/ddm/DdmHandleHello.java b/core/java/android/ddm/DdmHandleHello.java
index 2dce425..b2288fc 100644
--- a/core/java/android/ddm/DdmHandleHello.java
+++ b/core/java/android/ddm/DdmHandleHello.java
@@ -136,12 +136,14 @@
}
String vmFlags = "CheckJNI="
+ (vmRuntime.isCheckJniEnabled() ? "true" : "false");
+ boolean isNativeDebuggable = vmRuntime.isNativeDebuggable();
ByteBuffer out = ByteBuffer.allocate(28
+ vmIdent.length() * 2
+ appName.length() * 2
+ instructionSetDescription.length() * 2
- + vmFlags.length() * 2);
+ + vmFlags.length() * 2
+ + 1);
out.order(ChunkHandler.CHUNK_ORDER);
out.putInt(DdmServer.CLIENT_PROTOCOL_VERSION);
out.putInt(android.os.Process.myPid());
@@ -154,6 +156,7 @@
putString(out, instructionSetDescription);
out.putInt(vmFlags.length());
putString(out, vmFlags);
+ out.put((byte)(isNativeDebuggable ? 1 : 0));
Chunk reply = new Chunk(CHUNK_HELO, out);
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 63ee8d2..cc82eb6 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -186,7 +186,7 @@
* @see #TYPE_LINEAR_ACCELERATION
*/
public static final String STRING_TYPE_LINEAR_ACCELERATION =
- "android.sensor.linear_acceleration";
+ "android.sensor.linear_acceleration";
/**
* A constant describing a rotation vector sensor type.
@@ -229,7 +229,7 @@
* @see #TYPE_AMBIENT_TEMPERATURE
*/
public static final String STRING_TYPE_AMBIENT_TEMPERATURE =
- "android.sensor.ambient_temperature";
+ "android.sensor.ambient_temperature";
/**
* A constant describing an uncalibrated magnetic field sensor type.
@@ -254,7 +254,7 @@
* @see #TYPE_MAGNETIC_FIELD_UNCALIBRATED
*/
public static final String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED =
- "android.sensor.magnetic_field_uncalibrated";
+ "android.sensor.magnetic_field_uncalibrated";
/**
* A constant describing an uncalibrated rotation vector sensor type.
@@ -280,7 +280,7 @@
* @see #TYPE_GAME_ROTATION_VECTOR
*/
public static final String STRING_TYPE_GAME_ROTATION_VECTOR =
- "android.sensor.game_rotation_vector";
+ "android.sensor.game_rotation_vector";
/**
* A constant describing an uncalibrated gyroscope sensor type.
@@ -302,7 +302,7 @@
* @see #TYPE_GYROSCOPE_UNCALIBRATED
*/
public static final String STRING_TYPE_GYROSCOPE_UNCALIBRATED =
- "android.sensor.gyroscope_uncalibrated";
+ "android.sensor.gyroscope_uncalibrated";
/**
* A constant describing a significant motion trigger sensor.
@@ -324,7 +324,7 @@
* @see #TYPE_SIGNIFICANT_MOTION
*/
public static final String STRING_TYPE_SIGNIFICANT_MOTION =
- "android.sensor.significant_motion";
+ "android.sensor.significant_motion";
/**
* A constant describing a step detector sensor.
@@ -391,7 +391,7 @@
* @see #TYPE_GEOMAGNETIC_ROTATION_VECTOR
*/
public static final String STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR =
- "android.sensor.geomagnetic_rotation_vector";
+ "android.sensor.geomagnetic_rotation_vector";
/**
* A constant describing a heart rate monitor.
@@ -431,7 +431,7 @@
* A constant string describing a wake up tilt detector sensor type.
*
* @hide
- * @see #TYPE_WAKE_UP_TILT_DETECTOR
+ * @see #TYPE_TILT_DETECTOR
*/
public static final String SENSOR_STRING_TYPE_TILT_DETECTOR =
"android.sensor.tilt_detector";
@@ -495,7 +495,7 @@
*/
public static final String STRING_TYPE_GLANCE_GESTURE = "android.sensor.glance_gesture";
- /**
+ /**
* A constant describing a pick up sensor.
*
* A sensor of this type triggers when the device is picked up regardless of wherever it was
@@ -514,7 +514,7 @@
*/
public static final String STRING_TYPE_PICK_UP_GESTURE = "android.sensor.pick_up_gesture";
- /**
+ /**
* A constant describing a wrist tilt gesture sensor.
*
* A sensor of this type triggers when the device face is tilted towards the user.
@@ -553,7 +553,7 @@
*/
public static final String STRING_TYPE_DEVICE_ORIENTATION = "android.sensor.device_orientation";
- /**
+ /**
* A constant describing a pose sensor with 6 degrees of freedom.
*
* Similar to {@link #TYPE_ROTATION_VECTOR}, with additional delta
@@ -578,7 +578,7 @@
*/
public static final String STRING_TYPE_POSE_6DOF = "android.sensor.pose_6dof";
- /**
+ /**
* A constant describing a stationary detect sensor.
*
* See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
@@ -593,7 +593,7 @@
*/
public static final String STRING_TYPE_STATIONARY_DETECT = "android.sensor.stationary_detect";
- /**
+ /**
* A constant describing a motion detect sensor.
*
* See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
@@ -608,7 +608,7 @@
*/
public static final String STRING_TYPE_MOTION_DETECT = "android.sensor.motion_detect";
- /**
+ /**
* A constant describing a motion detect sensor.
*
* See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
@@ -706,6 +706,14 @@
private static final int DATA_INJECTION_MASK = 0x10;
private static final int DATA_INJECTION_SHIFT = 4;
+ // MASK for dynamic sensor (sensor that added during runtime), bit 6.
+ private static final int DYNAMIC_SENSOR_MASK = 0x20;
+ private static final int DYNAMIC_SENSOR_SHIFT = 5;
+
+ // MASK for indication bit of sensor additional information support (bit 7).
+ private static final int ADDITIONAL_INFO_MASK = 0x40;
+ private static final int ADDITIONAL_INFO_SHIFT = 6;
+
// TODO(): The following arrays are fragile and error-prone. This needs to be refactored.
// Note: This needs to be updated, whenever a new sensor is added.
@@ -887,13 +895,37 @@
}
/**
- * @return The type of this sensor as a string.
+ * @return The UUID of the sensor. If the sensor does not support UUID, the returned value will
+ * be an all zero UUID; if the sensor's combination of type and name is guaranteed to be unique
+ * in system, the return value will be an all "F" UUID.
+ *
+ * @hide
*/
+ @SystemApi
public UUID getUuid() {
return mUuid;
}
/**
+ * @return The unique id of sensor. Return value of 0 means this sensor does not support UUID;
+ * return value of -1 means this sensor can be uniquely identified in system by combination of
+ * its type and name.
+ */
+ public int getId() {
+ if (mUuid == ALL_0_UUID) {
+ return 0;
+ } else if (mUuid == ALL_F_UUID) {
+ return -1;
+ } else {
+ int id = Math.abs(mUuid.hashCode()) + 1;
+ if (id <= 0) { // catch corner case when hash is Integer.MIN_VALUE and Integer.MAX_VALUE
+ id = 1;
+ }
+ return id;
+ }
+ }
+
+ /**
* @hide
* @return The permission required to access this sensor. If empty, no permission is required.
*/
@@ -961,6 +993,26 @@
}
/**
+ * Returns true if the sensor is a dynamic sensor.
+ *
+ * @return <code>true</code> if the sensor is a dynamic sensor (sensor added at runtime).
+ * @see SensorManager.DynamicSensorCallback
+ */
+ public boolean isDynamicSensor() {
+ return (mFlags & DYNAMIC_SENSOR_MASK) != 0;
+ }
+
+ /**
+ * Returns true if the sensor supports sensor additional information API
+ *
+ * @return <code>true</code> if the sensor supports sensor additional information API
+ * @see SensorAdditionalInfo
+ */
+ public boolean isAdditionalInfoSupported() {
+ return (mFlags & ADDITIONAL_INFO_MASK) != 0;
+ }
+
+ /**
* Returns true if the sensor supports data injection when the
* HAL is set to data injection mode.
*
@@ -986,6 +1038,10 @@
+ ", power=" + mPower + ", minDelay=" + mMinDelay + "}";
}
+ //special UUID hash constant
+ private final static UUID ALL_0_UUID = new UUID(0,0);
+ private final static UUID ALL_F_UUID = new UUID(~0L, ~0L);
+
/**
* Sets the Type associated with the sensor.
* NOTE: to be used only by native bindings in SensorManager.
diff --git a/core/java/android/hardware/SensorAdditionalInfo.java b/core/java/android/hardware/SensorAdditionalInfo.java
index 8e5b8a3..572a287 100644
--- a/core/java/android/hardware/SensorAdditionalInfo.java
+++ b/core/java/android/hardware/SensorAdditionalInfo.java
@@ -27,7 +27,7 @@
* android.hardware.SensorEventCallback#onSensorAdditionalInfo onSensorAdditionalInfo}.
*
* @see SensorManager
- * @see SensorEventListener3
+ * @see SensorEventCallback
* @see Sensor
*
*/
@@ -106,7 +106,7 @@
* such as accelerometer, gyro, etc.
*
* Payload:
- * floatValues[0..11]: First 3 rows of a homogenous matrix in row major order that captures
+ * floatValues[0..11]: First 3 rows of a homogeneous matrix in row major order that captures
* any linear transformation, including rotation, scaling, shear, shift.
*/
public static final int TYPE_VEC3_CALIBRATION = 0x10002;
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 35c96f7..0d96b8e 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -18,7 +18,7 @@
/**
* This class represents a {@link android.hardware.Sensor Sensor} event and
- * holds informations such as the sensor's type, the time-stamp, accuracy and of
+ * holds information such as the sensor's type, the time-stamp, accuracy and of
* course the sensor's {@link SensorEvent#values data}.
*
* <p>
@@ -163,7 +163,7 @@
* </ul>
* <p>
* Typically the output of the gyroscope is integrated over time to
- * calculate a rotation describing the change of angles over the timestep,
+ * calculate a rotation describing the change of angles over the time step,
* for example:
* </p>
*
@@ -173,7 +173,7 @@
* private float timestamp;
*
* public void onSensorChanged(SensorEvent event) {
- * // This timestep's delta rotation to be multiplied by the current rotation
+ * // This time step's delta rotation to be multiplied by the current rotation
* // after computing it from the gyro sample data.
* if (timestamp != 0) {
* final float dT = (event.timestamp - timestamp) * NS2S;
@@ -192,8 +192,8 @@
* axisZ /= omegaMagnitude;
* }
*
- * // Integrate around this axis with the angular speed by the timestep
- * // in order to get a delta rotation from this sample over the timestep
+ * // Integrate around this axis with the angular speed by the time step
+ * // in order to get a delta rotation from this sample over the time step
* // We will convert this axis-angle representation of the delta rotation
* // into a quaternion before turning it into the rotation matrix.
* float thetaOverTwo = omegaMagnitude * dT / 2.0f;
@@ -433,9 +433,9 @@
* Each field is a component of the estimated hard iron calibration.
* The values are in micro-Tesla (uT).
* </p>
- * <p> Hard iron - These distortions arise due to the magnetized iron, steel or permanenet
+ * <p> Hard iron - These distortions arise due to the magnetized iron, steel or permanent
* magnets on the device.
- * Soft iron - These distortions arise due to the interaction with the earth's magentic
+ * Soft iron - These distortions arise due to the interaction with the earth's magnetic
* field.
* </p>
* <h4> {@link android.hardware.Sensor#TYPE_GAME_ROTATION_VECTOR}:</h4>
@@ -508,14 +508,14 @@
*
*
* <ul>
- * <li> values[0]: x*sin(θ/2) </li>
- * <li> values[1]: y*sin(θ/2) </li>
- * <li> values[2]: z*sin(θ/2) </li>
- * <li> values[3]: cos(θ/2) </li>
+ * <li> values[0]: x*sin(θ/2) </li>
+ * <li> values[1]: y*sin(θ/2) </li>
+ * <li> values[2]: z*sin(θ/2) </li>
+ * <li> values[3]: cos(θ/2) </li>
*
*
* <li> values[4]: Translation along x axis from an arbitrary origin. </li>
- * li> values[5]: Translation along y axis from an arbitrary origin. </li>
+ * <li> values[5]: Translation along y axis from an arbitrary origin. </li>
* <li> values[6]: Translation along z axis from an arbitrary origin. </li>
*
* <li> values[7]: Delta quaternion rotation x*sin(θ/2) </li>
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 5684aa5..a20307a 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -884,7 +884,7 @@
* Used for receiving notifications from the SensorManager when dynamic sensors are connected or
* disconnected.
*/
- public static abstract class DynamicSensorConnectionCallback {
+ public static abstract class DynamicSensorCallback {
/**
* Called when there is a dynamic sensor being connected to the system.
*
@@ -902,62 +902,73 @@
/**
- * Add a {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
- * DynamicSensorConnectionCallback} to receive dynamic sensor connection callbacks. Repeat
+ * Add a {@link android.hardware.SensorManager.DynamicSensorCallback
+ * DynamicSensorCallback} to receive dynamic sensor connection callbacks. Repeat
* registration with the already registered callback object will have no additional effect.
*
* @param callback An object that implements the
- * {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
- * DynamicSensorConnectionCallback}
+ * {@link android.hardware.SensorManager.DynamicSensorCallback
+ * DynamicSensorCallback}
* interface for receiving callbacks.
- * @see #addDynamicSensorCallback(DynamicSensorConnectionCallback, Handler)
+ * @see #addDynamicSensorCallback(DynamicSensorCallback, Handler)
*
* @throws IllegalArgumentException when callback is null.
*/
- public void registerDynamicSensorCallback(DynamicSensorConnectionCallback callback) {
+ public void registerDynamicSensorCallback(DynamicSensorCallback callback) {
registerDynamicSensorCallback(callback, null);
}
/**
- * Add a {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
- * DynamicSensorConnectionCallback} to receive dynamic sensor connection callbacks. Repeat
+ * Add a {@link android.hardware.SensorManager.DynamicSensorCallback
+ * DynamicSensorCallback} to receive dynamic sensor connection callbacks. Repeat
* registration with the already registered callback object will have no additional effect.
*
* @param callback An object that implements the
- * {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
- * DynamicSensorConnectionCallback} interface for receiving callbacks.
+ * {@link android.hardware.SensorManager.DynamicSensorCallback
+ * DynamicSensorCallback} interface for receiving callbacks.
* @param handler The {@link android.os.Handler Handler} the {@link
- * android.hardware.SensorManager.DynamicSensorConnectionCallback
+ * android.hardware.SensorManager.DynamicSensorCallback
* sensor connection events} will be delivered to.
*
* @throws IllegalArgumentException when callback is null.
*/
public void registerDynamicSensorCallback(
- DynamicSensorConnectionCallback callback, Handler handler) {
+ DynamicSensorCallback callback, Handler handler) {
registerDynamicSensorCallbackImpl(callback, handler);
}
/**
- * Remove a {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
- * DynamicSensorConnectionCallback} to stop sending dynamic sensor connection events to that
+ * Remove a {@link android.hardware.SensorManager.DynamicSensorCallback
+ * DynamicSensorCallback} to stop sending dynamic sensor connection events to that
* callback.
*
* @param callback An object that implements the
- * {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
- * DynamicSensorConnectionCallback}
+ * {@link android.hardware.SensorManager.DynamicSensorCallback
+ * DynamicSensorCallback}
* interface for receiving callbacks.
*/
- public void unregisterDynamicSensorCallback(DynamicSensorConnectionCallback callback) {
+ public void unregisterDynamicSensorCallback(DynamicSensorCallback callback) {
unregisterDynamicSensorCallbackImpl(callback);
}
+ /**
+ * Tell if dynamic sensor discovery feature is supported by system.
+ *
+ * @return <code>true</code> if dynamic sensor discovery is supported, <code>false</code>
+ * otherwise.
+ */
+ public boolean isDynamicSensorDiscoverySupported() {
+ List<Sensor> sensors = getSensorList(Sensor.TYPE_DYNAMIC_SENSOR_META);
+ return sensors.size() > 0;
+ }
+
/** @hide */
protected abstract void registerDynamicSensorCallbackImpl(
- DynamicSensorConnectionCallback callback, Handler handler);
+ DynamicSensorCallback callback, Handler handler);
/** @hide */
protected abstract void unregisterDynamicSensorCallbackImpl(
- DynamicSensorConnectionCallback callback);
+ DynamicSensorCallback callback);
/**
* <p>
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 7d903bd..259ca03 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -1,4 +1,4 @@
- /*
+/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -76,7 +76,7 @@
new HashMap<TriggerEventListener, TriggerEventQueue>();
// Dynamic Sensor callbacks
- private HashMap<DynamicSensorConnectionCallback, Handler>
+ private HashMap<DynamicSensorCallback, Handler>
mDynamicSensorCallbacks = new HashMap<>();
private BroadcastReceiver mDynamicSensorBroadcastReceiver;
@@ -120,7 +120,7 @@
@Override
protected List<Sensor> getFullDynamicSensorList() {
// only set up broadcast receiver if the application tries to find dynamic sensors or
- // explicitly register a DynamicSensorConnectionCallback
+ // explicitly register a DynamicSensorCallback
setupDynamicSensorBroadcastReceiver();
updateDynamicSensorList();
return mFullDynamicSensorsList;
@@ -354,9 +354,9 @@
Handler mainHandler = new Handler(mContext.getMainLooper());
- for (Map.Entry<DynamicSensorConnectionCallback, Handler> entry :
+ for (Map.Entry<DynamicSensorCallback, Handler> entry :
mDynamicSensorCallbacks.entrySet()) {
- final DynamicSensorConnectionCallback callback = entry.getKey();
+ final DynamicSensorCallback callback = entry.getKey();
Handler handler =
entry.getValue() == null ? mainHandler : entry.getValue();
@@ -413,7 +413,7 @@
/** @hide */
protected void registerDynamicSensorCallbackImpl(
- DynamicSensorConnectionCallback callback, Handler handler) {
+ DynamicSensorCallback callback, Handler handler) {
if (DEBUG_DYNAMIC_SENSOR) {
Log.i(TAG, "DYNS Register dynamic sensor callback");
}
@@ -432,7 +432,7 @@
/** @hide */
protected void unregisterDynamicSensorCallbackImpl(
- DynamicSensorConnectionCallback callback) {
+ DynamicSensorCallback callback) {
if (DEBUG_DYNAMIC_SENSOR) {
Log.i(TAG, "Removing dynamic sensor listerner");
}
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 4add962..d06e08b 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -2025,11 +2025,20 @@
* produced in response to a capture request submitted
* while in HDR mode.</p>
* <p>Since substantial post-processing is generally needed to
- * produce an HDR image, only YUV and JPEG outputs are
- * supported for LIMITED/FULL device HDR captures, and only
- * JPEG outputs are supported for LEGACY HDR
- * captures. Using a RAW output for HDR capture is not
+ * produce an HDR image, only YUV, PRIVATE, and JPEG
+ * outputs are supported for LIMITED/FULL device HDR
+ * captures, and only JPEG outputs are supported for LEGACY
+ * HDR captures. Using a RAW output for HDR capture is not
* supported.</p>
+ * <p>Some devices may also support always-on HDR, which
+ * applies HDR processing at full frame rate. For these
+ * devices, intents other than STILL_CAPTURE will also
+ * produce an HDR output with no frame rate impact compared
+ * to normal operation, though the quality may be lower
+ * than for STILL_CAPTURE intents.</p>
+ * <p>If SCENE_MODE_HDR is used with unsupported output types
+ * or capture intents, the images captured will be as if
+ * the SCENE_MODE was not enabled at all.</p>
*
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
* @see CaptureRequest#CONTROL_SCENE_MODE
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 5748726..4f41e1c 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -3373,7 +3373,7 @@
/**
* <p>Maximum raw value output by sensor for this frame.</p>
- * <p>Since the android.sensor.blackLevel may change for different
+ * <p>Since the {@link CameraCharacteristics#SENSOR_BLACK_LEVEL_PATTERN android.sensor.blackLevelPattern} may change for different
* capture settings (e.g., {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}), the white
* level will change accordingly. This key is similar to
* {@link CameraCharacteristics#SENSOR_INFO_WHITE_LEVEL android.sensor.info.whiteLevel}, but specifies the camera device
@@ -3385,6 +3385,7 @@
* >= 0</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
+ * @see CameraCharacteristics#SENSOR_BLACK_LEVEL_PATTERN
* @see CameraCharacteristics#SENSOR_INFO_WHITE_LEVEL
* @see CameraCharacteristics#SENSOR_OPTICAL_BLACK_REGIONS
* @see CaptureRequest#SENSOR_SENSITIVITY
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
index 2c2ad1c..b0b94e3 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
@@ -70,7 +70,7 @@
* CameraDeviceStateListener callbacks to be called after state transitions.
*/
public interface CameraDeviceStateListener {
- void onError(int errorCode, RequestHolder holder);
+ void onError(int errorCode, Object errorArg, RequestHolder holder);
void onConfiguring();
void onIdle();
void onBusy();
@@ -162,11 +162,12 @@
* @param captureError Report a recoverable error for a single buffer or result using a valid
* error code for {@code ICameraDeviceCallbacks}, or
* {@link #NO_CAPTURE_ERROR}.
+ * @param captureErrorArg An argument for some error captureError codes.
* @return {@code false} if an error has occurred.
*/
public synchronized boolean setCaptureResult(final RequestHolder request,
- final CameraMetadataNative result,
- final int captureError) {
+ final CameraMetadataNative result,
+ final int captureError, final Object captureErrorArg) {
if (mCurrentState != STATE_CAPTURING) {
Log.e(TAG, "Cannot receive result while in state: " + mCurrentState);
mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE;
@@ -179,7 +180,7 @@
mCurrentHandler.post(new Runnable() {
@Override
public void run() {
- mCurrentListener.onError(captureError, request);
+ mCurrentListener.onError(captureError, captureErrorArg, request);
}
});
} else {
@@ -194,6 +195,11 @@
return mCurrentError == NO_CAPTURE_ERROR;
}
+ public synchronized boolean setCaptureResult(final RequestHolder request,
+ final CameraMetadataNative result) {
+ return setCaptureResult(request, result, NO_CAPTURE_ERROR, /*errorArg*/null);
+ }
+
/**
* Set the listener for state transition callbacks.
*
@@ -239,7 +245,7 @@
mCurrentHandler.post(new Runnable() {
@Override
public void run() {
- mCurrentListener.onError(mCurrentError, mCurrentRequest);
+ mCurrentListener.onError(mCurrentError, /*errorArg*/null, mCurrentRequest);
}
});
}
@@ -299,7 +305,7 @@
mCurrentHandler.post(new Runnable() {
@Override
public void run() {
- mCurrentListener.onError(error, mCurrentRequest);
+ mCurrentListener.onError(error, /*errorArg*/null, mCurrentRequest);
}
});
} else {
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index d01c275..f99928a 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -480,19 +480,15 @@
throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
- ArrayList<Surface> surfaces = null;
+ SparseArray<Surface> surfaces = null;
synchronized(mConfigureLock) {
if (!mConfiguring) {
String err = "Cannot end configure, no configuration change in progress.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
- int numSurfaces = mSurfaces.size();
- if (numSurfaces > 0) {
- surfaces = new ArrayList<>();
- for (int i = 0; i < numSurfaces; ++i) {
- surfaces.add(mSurfaces.valueAt(i));
- }
+ if (mSurfaces != null) {
+ surfaces = mSurfaces.clone();
}
mConfiguring = false;
}
diff --git a/core/java/android/hardware/camera2/legacy/CaptureCollector.java b/core/java/android/hardware/camera2/legacy/CaptureCollector.java
index eb48a01..113927c 100644
--- a/core/java/android/hardware/camera2/legacy/CaptureCollector.java
+++ b/core/java/android/hardware/camera2/legacy/CaptureCollector.java
@@ -19,7 +19,7 @@
import android.util.Log;
import android.util.MutableLong;
import android.util.Pair;
-
+import android.view.Surface;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.TreeSet;
@@ -95,22 +95,28 @@
} else {
// Send buffer dropped errors for each pending buffer if the request has
// started.
- if (mFailedPreview) {
- Log.w(TAG, "Preview buffers dropped for request: " +
- mRequest.getRequestId());
- for (int i = 0; i < mRequest.numPreviewTargets(); i++) {
- CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
- /*result*/null,
- CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_BUFFER);
- }
- }
- if (mFailedJpeg) {
- Log.w(TAG, "Jpeg buffers dropped for request: " +
- mRequest.getRequestId());
- for (int i = 0; i < mRequest.numJpegTargets(); i++) {
- CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
- /*result*/null,
- CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_BUFFER);
+ for (Surface targetSurface : mRequest.getRequest().getTargets() ) {
+ try {
+ if (mRequest.jpegType(targetSurface)) {
+ if (mFailedJpeg) {
+ CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
+ /*result*/null,
+ CameraDeviceImpl.CameraDeviceCallbacks.
+ ERROR_CAMERA_BUFFER,
+ targetSurface);
+ }
+ } else {
+ // preview buffer
+ if (mFailedPreview) {
+ CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
+ /*result*/null,
+ CameraDeviceImpl.CameraDeviceCallbacks.
+ ERROR_CAMERA_BUFFER,
+ targetSurface);
+ }
+ }
+ } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
+ Log.e(TAG, "Unexpected exception when querying Surface: " + e);
}
}
}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index 661edd7..6c95869 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -36,6 +36,7 @@
import android.util.Log;
import android.util.Pair;
import android.util.Size;
+import android.util.SparseArray;
import android.view.Surface;
import java.util.ArrayList;
@@ -64,7 +65,7 @@
private final CameraCharacteristics mStaticCharacteristics;
private final ICameraDeviceCallbacks mDeviceCallbacks;
private final CameraDeviceState mDeviceState = new CameraDeviceState();
- private List<Surface> mConfiguredSurfaces;
+ private SparseArray<Surface> mConfiguredSurfaces;
private boolean mClosed = false;
private final ConditionVariable mIdle = new ConditionVariable(/*open*/true);
@@ -89,13 +90,29 @@
public static final int NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW = 1;
private CaptureResultExtras getExtrasFromRequest(RequestHolder holder) {
+ return getExtrasFromRequest(holder,
+ /*errorCode*/CameraDeviceState.NO_CAPTURE_ERROR, /*errorArg*/null);
+ }
+
+ private CaptureResultExtras getExtrasFromRequest(RequestHolder holder,
+ int errorCode, Object errorArg) {
+ int errorStreamId = -1;
+ if (errorCode == CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_BUFFER) {
+ Surface errorTarget = (Surface) errorArg;
+ int indexOfTarget = mConfiguredSurfaces.indexOfValue(errorTarget);
+ if (indexOfTarget < 0) {
+ Log.e(TAG, "Buffer drop error reported for unknown Surface");
+ } else {
+ errorStreamId = mConfiguredSurfaces.keyAt(indexOfTarget);
+ }
+ }
if (holder == null) {
return new CaptureResultExtras(ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE,
ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE);
}
return new CaptureResultExtras(holder.getRequestId(), holder.getSubsequeceId(),
/*afTriggerId*/0, /*precaptureTriggerId*/0, holder.getFrameNumber(),
- /*partialResultCount*/1, /*errorStreamId*/-1);
+ /*partialResultCount*/1, errorStreamId);
}
/**
@@ -105,9 +122,9 @@
private final CameraDeviceState.CameraDeviceStateListener mStateListener =
new CameraDeviceState.CameraDeviceStateListener() {
@Override
- public void onError(final int errorCode, final RequestHolder holder) {
+ public void onError(final int errorCode, final Object errorArg, final RequestHolder holder) {
if (DEBUG) {
- Log.d(TAG, "onError called, errorCode = " + errorCode);
+ Log.d(TAG, "onError called, errorCode = " + errorCode + ", errorArg = " + errorArg);
}
switch (errorCode) {
/*
@@ -125,7 +142,7 @@
}
}
- final CaptureResultExtras extras = getExtrasFromRequest(holder);
+ final CaptureResultExtras extras = getExtrasFromRequest(holder, errorCode, errorArg);
mResultHandler.post(new Runnable() {
@Override
public void run() {
@@ -281,14 +298,17 @@
*
* <p>Every surface in {@code outputs} must be non-{@code null}.</p>
*
- * @param outputs a list of surfaces to set.
+ * @param outputs a list of surfaces to set. LegacyCameraDevice will take ownership of this
+ * list; it must not be modified by the caller once it's passed in.
* @return an error code for this binder operation, or {@link NO_ERROR}
* on success.
*/
- public int configureOutputs(List<Surface> outputs) {
+ public int configureOutputs(SparseArray<Surface> outputs) {
List<Pair<Surface, Size>> sizedSurfaces = new ArrayList<>();
if (outputs != null) {
- for (Surface output : outputs) {
+ int count = outputs.size();
+ for (int i = 0; i < count; i++) {
+ Surface output = outputs.valueAt(i);
if (output == null) {
Log.e(TAG, "configureOutputs - null outputs are not allowed");
return BAD_VALUE;
@@ -353,7 +373,7 @@
}
if (success) {
- mConfiguredSurfaces = outputs != null ? new ArrayList<>(outputs) : null;
+ mConfiguredSurfaces = outputs;
} else {
return LegacyExceptionUtils.INVALID_OPERATION;
}
@@ -659,6 +679,23 @@
return nativeGetSurfaceId(surface);
}
+ static List<Long> getSurfaceIds(SparseArray<Surface> surfaces) {
+ if (surfaces == null) {
+ throw new NullPointerException("Null argument surfaces");
+ }
+ List<Long> surfaceIds = new ArrayList<>();
+ int count = surfaces.size();
+ for (int i = 0; i < count; i++) {
+ long id = getSurfaceId(surfaces.valueAt(i));
+ if (id == 0) {
+ throw new IllegalStateException(
+ "Configured surface had null native GraphicBufferProducer pointer!");
+ }
+ surfaceIds.add(id);
+ }
+ return surfaceIds;
+ }
+
static List<Long> getSurfaceIds(Collection<Surface> surfaces) {
if (surfaces == null) {
throw new NullPointerException("Null argument surfaces");
diff --git a/core/java/android/hardware/camera2/legacy/RequestHolder.java b/core/java/android/hardware/camera2/legacy/RequestHolder.java
index 9b628fb..476c3de 100644
--- a/core/java/android/hardware/camera2/legacy/RequestHolder.java
+++ b/core/java/android/hardware/camera2/legacy/RequestHolder.java
@@ -41,6 +41,8 @@
private final int mNumPreviewTargets;
private volatile boolean mFailed = false;
+ private final Collection<Long> mJpegSurfaceIds;
+
/**
* A builder class for {@link RequestHolder} objects.
*
@@ -150,13 +152,13 @@
*/
public RequestHolder build(long frameNumber) {
return new RequestHolder(mRequestId, mSubsequenceId, mRequest, mRepeating, frameNumber,
- mNumJpegTargets, mNumPreviewTargets);
+ mNumJpegTargets, mNumPreviewTargets, mJpegSurfaceIds);
}
}
private RequestHolder(int requestId, int subsequenceId, CaptureRequest request,
boolean repeating, long frameNumber, int numJpegTargets,
- int numPreviewTargets) {
+ int numPreviewTargets, Collection<Long> jpegSurfaceIds) {
mRepeating = repeating;
mRequest = request;
mRequestId = requestId;
@@ -164,6 +166,7 @@
mFrameNumber = frameNumber;
mNumJpegTargets = numJpegTargets;
mNumPreviewTargets = numPreviewTargets;
+ mJpegSurfaceIds = jpegSurfaceIds;
}
/**
@@ -238,6 +241,17 @@
}
/**
+ * Returns true if the given surface requires jpeg buffers.
+ *
+ * @param s a {@link android.view.Surface} to check.
+ * @return true if the surface requires a jpeg buffer.
+ */
+ public boolean jpegType(Surface s)
+ throws LegacyExceptionUtils.BufferQueueAbandonedException {
+ return LegacyCameraDevice.containsSurfaceId(s, mJpegSurfaceIds);
+ }
+
+ /**
* Mark this request as failed.
*/
public void failRequest() {
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index e8ce3ec..a3fdd56 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -908,8 +908,7 @@
mFaceDetectMapper.mapResultFaces(result, mLastRequest);
if (!holder.requestFailed()) {
- mDeviceState.setCaptureResult(holder, result,
- CameraDeviceState.NO_CAPTURE_ERROR);
+ mDeviceState.setCaptureResult(holder, result);
}
}
if (DEBUG) {
diff --git a/core/java/android/hardware/location/ContextHubInfo.java b/core/java/android/hardware/location/ContextHubInfo.java
index 644e29f..ae44f1d 100644
--- a/core/java/android/hardware/location/ContextHubInfo.java
+++ b/core/java/android/hardware/location/ContextHubInfo.java
@@ -37,6 +37,7 @@
private float mStoppedPowerDrawMw;
private float mSleepPowerDrawMw;
private float mPeakPowerDrawMw;
+ private int mMaxPacketLengthBytes;
private int[] mSupportedSensors;
@@ -46,6 +47,27 @@
}
/**
+ * returns the maximum number of bytes that can be sent per message to the hub
+ *
+ * @return int - maximum bytes that can be transmitted in a
+ * single packet
+ */
+ public int getMaxPacketLengthBytes() {
+ return mMaxPacketLengthBytes;
+ }
+
+ /**
+ * set the context hub unique identifer
+ *
+ * @param bytes - Maximum number of bytes per message
+ *
+ * @hide
+ */
+ public void setMaxPacketLenBytes(int bytes) {
+ mMaxPacketLengthBytes = bytes;
+ }
+
+ /**
* get the context hub unique identifer
*
* @return int - unique system wide identifier
@@ -374,4 +396,4 @@
return new ContextHubInfo[size];
}
};
-}
+}
\ No newline at end of file
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 4ddf767..89edaa9 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -43,23 +43,6 @@
private Handler mCallbackHandler;
/**
- * A special context hub identifier meaning any possible hub on the system.
- */
- public static final int ANY_HUB = -1;
- /**
- * A constant denoting a message to load a a Nano App
- */
- public static final int MSG_LOAD_NANO_APP = 1;
- /**
- * A constant denoting a message to unload a a Nano App
- */
- public static final int MSG_UNLOAD_NANO_APP = 2;
- /**
- * A constant denoting a message to send a message
- */
- public static final int MSG_DATA_SEND = 3;
-
- /**
* An interface to receive asynchronous communication from the context hub.
*/
public abstract static class Callback {
@@ -69,7 +52,7 @@
* Callback function called on message receipt from context hub.
*
* @param hubHandle Handle (system-wide unique identifier) of the hub of the message.
- * @param nanoAppHandle Handle (unique identifier) for the app that sent the message.
+ * @param nanoAppHandle Handle (unique identifier) for app instance that sent the message.
* @param message The context hub message.
*
* @see ContextHubMessage
@@ -89,7 +72,7 @@
try {
retVal = getBinder().getContextHubHandles();
} catch (RemoteException e) {
- Log.e(TAG, "Could not fetch context hub handles : " + e);
+ Log.w(TAG, "Could not fetch context hub handles : " + e);
}
return retVal;
}
@@ -107,7 +90,7 @@
try {
retVal = getBinder().getContextHubInfo(hubHandle);
} catch (RemoteException e) {
- Log.e(TAG, "Could not fetch context hub info :" + e);
+ Log.w(TAG, "Could not fetch context hub info :" + e);
}
return retVal;
@@ -126,6 +109,7 @@
*/
public int loadNanoApp(int hubHandle, NanoApp app) {
int retVal = -1;
+
if (app == null) {
return retVal;
}
@@ -133,7 +117,7 @@
try {
retVal = getBinder().loadNanoApp(hubHandle, app);
} catch (RemoteException e) {
- Log.e(TAG, "Could not fetch load nanoApp :" + e);
+ Log.w(TAG, "Could not load nanoApp :" + e);
}
return retVal;
@@ -152,7 +136,7 @@
try {
retVal = getBinder().unloadNanoApp(nanoAppHandle);
} catch (RemoteException e) {
- Log.e(TAG, "Could not fetch unload nanoApp :" + e);
+ Log.w(TAG, "Could not fetch unload nanoApp :" + e);
}
return retVal;
@@ -172,7 +156,7 @@
try {
retVal = getBinder().getNanoAppInstanceInfo(nanoAppHandle);
} catch (RemoteException e) {
- Log.e(TAG, "Could not fetch nanoApp info :" + e);
+ Log.w(TAG, "Could not fetch nanoApp info :" + e);
}
return retVal;
@@ -193,7 +177,7 @@
try {
retVal = getBinder().findNanoAppOnHub(hubHandle, filter);
} catch (RemoteException e) {
- Log.e(TAG, "Could not query nanoApp instance :" + e);
+ Log.w(TAG, "Could not query nanoApp instance :" + e);
}
return retVal;
}
@@ -212,10 +196,14 @@
public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage message) {
int retVal = -1;
+ if (message == null || message.getData() == null) {
+ Log.w(TAG, "null ptr");
+ return retVal;
+ }
try {
retVal = getBinder().sendMessage(hubHandle, nanoAppHandle, message);
} catch (RemoteException e) {
- Log.e(TAG, "Could not fetch send message :" + e.toString());
+ Log.w(TAG, "Could not send message :" + e.toString());
}
return retVal;
@@ -247,7 +235,7 @@
public int registerCallback(Callback callback, Handler handler) {
synchronized(this) {
if (mCallback != null) {
- Log.e(TAG, "Max number of callbacks reached!");
+ Log.w(TAG, "Max number of callbacks reached!");
return -1;
}
mCallback = callback;
@@ -268,7 +256,7 @@
public int unregisterCallback(Callback callback) {
synchronized(this) {
if (callback != mCallback) {
- Log.e(TAG, "Cannot recognize callback!");
+ Log.w(TAG, "Cannot recognize callback!");
return -1;
}
@@ -311,11 +299,11 @@
try {
getBinder().registerCallback(mClientCallback);
} catch (RemoteException e) {
- Log.e(TAG, "Could not register callback:" + e);
+ Log.w(TAG, "Could not register callback:" + e);
}
} else {
- Log.d(TAG, "failed to getService");
+ Log.w(TAG, "failed to getService");
}
}
diff --git a/core/java/android/hardware/location/ContextHubMessage.java b/core/java/android/hardware/location/ContextHubMessage.java
index 954e97d..bca2ae6 100644
--- a/core/java/android/hardware/location/ContextHubMessage.java
+++ b/core/java/android/hardware/location/ContextHubMessage.java
@@ -16,10 +16,10 @@
package android.hardware.location;
-
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Log;
import java.util.Arrays;
@@ -32,6 +32,9 @@
private int mVersion;
private byte[]mData;
+ private static final String TAG = "ContextHubMessage";
+
+
/**
* Get the message type
*
@@ -106,9 +109,11 @@
private ContextHubMessage(Parcel in) {
mType = in.readInt();
mVersion = in.readInt();
- byte[] byteBuffer = new byte[in.readInt()];
- in.readByteArray(byteBuffer);
+ int bufferLength = in.readInt();
+ mData = new byte[bufferLength];
+ in.readByteArray(mData);
}
+
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mType);
out.writeInt(mVersion);
diff --git a/core/java/android/hardware/location/ContextHubService.java b/core/java/android/hardware/location/ContextHubService.java
index 274babe..3e6cb63 100644
--- a/core/java/android/hardware/location/ContextHubService.java
+++ b/core/java/android/hardware/location/ContextHubService.java
@@ -29,12 +29,30 @@
*/
public class ContextHubService extends IContextHubService.Stub {
+ public static final String CONTEXTHUB_SERVICE = "contexthub_service";
+
private static final String TAG = "ContextHubService";
private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE;
private static final String ENFORCE_HW_PERMISSION_MESSAGE = "Permission '"
+ HARDWARE_PERMISSION + "' not granted to access ContextHub Hardware";
- public static final String CONTEXTHUB_SERVICE = "contexthub_service";
+
+ public static final int ANY_HUB = -1;
+ public static final int MSG_LOAD_NANO_APP = 3;
+ public static final int MSG_UNLOAD_NANO_APP = 4;
+
+ private static final String PRE_LOADED_GENERIC_UNKNOWN = "Preloaded app, unknown";
+ private static final String PRE_LOADED_APP_NAME = PRE_LOADED_GENERIC_UNKNOWN;
+ private static final String PRE_LOADED_APP_PUBLISHER = PRE_LOADED_GENERIC_UNKNOWN;
+ private static final int PRE_LOADED_APP_MEM_REQ = 0;
+
+ private static final int MSG_HEADER_SIZE = 4;
+ private static final int MSG_FIELD_TYPE = 0;
+ private static final int MSG_FIELD_VERSION = 1;
+ private static final int MSG_FIELD_HUB_HANDLE = 2;
+ private static final int MSG_FIELD_APP_INSTANCE = 3;
+
+ private static final int OS_APP_INSTANCE = -1;
private final Context mContext;
@@ -42,44 +60,27 @@
private ContextHubInfo[] mContextHubInfo;
private IContextHubCallback mCallback;
+ private native int nativeSendMessage(int[] header, byte[] data);
+ private native ContextHubInfo[] nativeInitialize();
+
+
public ContextHubService(Context context) {
mContext = context;
mContextHubInfo = nativeInitialize();
+ mNanoAppHash = new HashMap<Integer, NanoAppInstanceInfo>();
for (int i = 0; i < mContextHubInfo.length; i++) {
- Log.v(TAG, "ContextHub[" + i + "] id: " + mContextHubInfo[i].getId()
+ Log.d(TAG, "ContextHub[" + i + "] id: " + mContextHubInfo[i].getId()
+ ", name: " + mContextHubInfo[i].getName());
}
}
- private native int nativeSendMessage(int[] header, byte[] data);
- private native ContextHubInfo[] nativeInitialize();
-
@Override
- public int registerCallback(IContextHubCallback callback) throws RemoteException{
+ public int registerCallback(IContextHubCallback callback) throws RemoteException {
checkPermissions();
- mCallback = callback;
- return 0;
- }
-
-
- private int onMessageReceipt(int[] header, byte[] data) {
- if (mCallback != null) {
- // TODO : Defend against unexpected header sizes
- // Add abstraction for magic numbers
- // onMessageRecipt should pass the right arguments
- ContextHubMessage msg = new ContextHubMessage(header[0], header[1], data);
-
- try {
- mCallback.onMessageReceipt(0, 0, msg);
- } catch (Exception e) {
- Log.e(TAG, "Exception " + e + " when calling remote callback");
- return -1;
- }
- } else {
- Log.d(TAG, "Message Callback is NULL");
+ synchronized(this) {
+ mCallback = callback;
}
-
return 0;
}
@@ -118,14 +119,17 @@
}
// Call Native interface here
- int[] msgHeader = new int[8];
- msgHeader[0] = contextHubHandle;
- msgHeader[1] = app.getAppId();
- msgHeader[2] = app.getAppVersion();
- msgHeader[3] = ContextHubManager.MSG_LOAD_NANO_APP;
- msgHeader[4] = 0; // Loading hints
+ int[] msgHeader = new int[MSG_HEADER_SIZE];
+ msgHeader[MSG_FIELD_HUB_HANDLE] = contextHubHandle;
+ msgHeader[MSG_FIELD_APP_INSTANCE] = OS_APP_INSTANCE;
+ msgHeader[MSG_FIELD_VERSION] = 0;
+ msgHeader[MSG_FIELD_TYPE] = MSG_LOAD_NANO_APP;
- return nativeSendMessage(msgHeader, app.getAppBinary());
+ if (nativeSendMessage(msgHeader, app.getAppBinary()) != 0) {
+ return -1;
+ }
+ // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
+ return 0;
}
@Override
@@ -137,12 +141,18 @@
}
// Call Native interface here
- int[] msgHeader = new int[8];
- msgHeader[0] = info.getContexthubId();
- msgHeader[1] = ContextHubManager.MSG_UNLOAD_NANO_APP;
- msgHeader[2] = info.getHandle();
+ int[] msgHeader = new int[MSG_HEADER_SIZE];
+ msgHeader[MSG_FIELD_HUB_HANDLE] = ANY_HUB;
+ msgHeader[MSG_FIELD_APP_INSTANCE] = OS_APP_INSTANCE;
+ msgHeader[MSG_FIELD_VERSION] = 0;
+ msgHeader[MSG_FIELD_TYPE] = MSG_UNLOAD_NANO_APP;
- return nativeSendMessage(msgHeader, null);
+ if(nativeSendMessage(msgHeader, null) != 0) {
+ return -1;
+ }
+
+ // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
+ return 0;
}
@Override
@@ -166,7 +176,7 @@
for(Integer nanoAppInstance : mNanoAppHash.keySet()) {
NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstance);
- if(filter.testMatch(info)){
+ if (filter.testMatch(info)){
foundInstances.add(nanoAppInstance);
}
}
@@ -183,12 +193,12 @@
public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg)
throws RemoteException {
checkPermissions();
- int[] msgHeader = new int[8];
- msgHeader[0] = ContextHubManager.MSG_DATA_SEND;
- msgHeader[1] = hubHandle;
- msgHeader[2] = nanoAppHandle;
- msgHeader[3] = msg.getMsgType();
- msgHeader[4] = msg.getVersion();
+
+ int[] msgHeader = new int[MSG_HEADER_SIZE];
+ msgHeader[MSG_FIELD_HUB_HANDLE] = hubHandle;
+ msgHeader[MSG_FIELD_APP_INSTANCE] = nanoAppHandle;
+ msgHeader[MSG_FIELD_VERSION] = msg.getVersion();
+ msgHeader[MSG_FIELD_TYPE] = msg.getMsgType();
return nativeSendMessage(msgHeader, msg.getData());
}
@@ -196,5 +206,52 @@
private void checkPermissions() {
mContext.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE);
}
-}
+ private int onMessageReceipt(int[] header, byte[] data) {
+ if (header == null || data == null || header.length < MSG_HEADER_SIZE) {
+ return -1;
+ }
+
+ synchronized(this) {
+ if (mCallback != null) {
+ ContextHubMessage msg = new ContextHubMessage(header[MSG_FIELD_TYPE],
+ header[MSG_FIELD_VERSION],
+ data);
+
+ try {
+ mCallback.onMessageReceipt(header[MSG_FIELD_HUB_HANDLE],
+ header[MSG_FIELD_APP_INSTANCE],
+ msg);
+ } catch (Exception e) {
+ Log.w(TAG, "Exception " + e + " when calling remote callback");
+ return -1;
+ }
+ } else {
+ Log.d(TAG, "Message Callback is NULL");
+ }
+ }
+
+ return 0;
+ }
+
+ private int addAppInstance(int hubHandle, int appInstanceHandle, long appId, int appVersion) {
+ // App Id encodes vendor & version
+ NanoAppInstanceInfo appInfo = new NanoAppInstanceInfo();
+
+ appInfo.setAppId(appId);
+ appInfo.setAppVersion(appVersion);
+ appInfo.setName(PRE_LOADED_APP_NAME);
+ appInfo.setContexthubId(hubHandle);
+ appInfo.setHandle(appInstanceHandle);
+ appInfo.setPublisher(PRE_LOADED_APP_PUBLISHER);
+ appInfo.setNeededExecMemBytes(PRE_LOADED_APP_MEM_REQ);
+ appInfo.setNeededReadMemBytes(PRE_LOADED_APP_MEM_REQ);
+ appInfo.setNeededWriteMemBytes(PRE_LOADED_APP_MEM_REQ);
+
+ mNanoAppHash.put(appInstanceHandle, appInfo);
+ Log.d(TAG, "Added app instance " + appInstanceHandle + " with id " + appId
+ + " version " + appVersion);
+
+ return 0;
+ }
+}
diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
index 369f9e4..8db70e9 100644
--- a/core/java/android/hardware/location/NanoAppFilter.java
+++ b/core/java/android/hardware/location/NanoAppFilter.java
@@ -20,6 +20,7 @@
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Log;
/**
* @hide
@@ -27,6 +28,8 @@
@SystemApi
public class NanoAppFilter {
+ private static final String TAG = "NanoAppFilter";
+
// The appId, can be set to APP_ID_ANY
private long mAppId;
@@ -54,6 +57,10 @@
* If this flag is set, only versions strictly less than the version specified shall match.
*/
public static final int FLAGS_VERSION_LESS_THAN = 4;
+ /**
+ * If this flag is set, only versions strictly equal to the
+ * version specified shall match.
+ */
public static final int FLAGS_VERSION_STRICTLY_EQUAL = 8;
/**
@@ -117,14 +124,9 @@
* @return true if this is a match, false otherwise
*/
public boolean testMatch(NanoAppInstanceInfo info) {
- if ((mContextHubId == HUB_ANY || info.getContexthubId() == mContextHubId) &&
+ return (mContextHubId == HUB_ANY || info.getContexthubId() == mContextHubId) &&
(mAppId == APP_ANY || info.getAppId() == mAppId) &&
- // (mAppIdVendorMask == VENDOR_ANY) TODO : Expose Vendor mask cleanly
- (versionsMatch(mVersionRestrictionMask, mAppVersion, info.getAppVersion()))) {
- return true;
- } else {
- return false;
- }
+ (versionsMatch(mVersionRestrictionMask, mAppVersion, info.getAppVersion()));
}
public static final Parcelable.Creator<NanoAppFilter> CREATOR
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
index ac62919..977f645 100644
--- a/core/java/android/hardware/location/NanoAppInstanceInfo.java
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
@@ -29,7 +29,7 @@
private String mPublisher;
private String mName;
- private int mAppId;
+ private long mAppId;
private int mAppVersion;
private int mNeededReadMemBytes;
@@ -59,6 +59,8 @@
* set the publisher name for the app
*
* @param publisher - name of the publisher
+ *
+ * @hide
*/
public void setPublisher(String publisher) {
mPublisher = publisher;
@@ -77,6 +79,8 @@
* set the name of the app
*
* @param name - name of the app
+ *
+ * @hide
*/
public void setName(String name) {
mName = name;
@@ -87,7 +91,7 @@
*
* @return int - application identifier
*/
- public int getAppId() {
+ public long getAppId() {
return mAppId;
}
@@ -95,8 +99,10 @@
* Set the application identifier
*
* @param appId - application identifier
+ *
+ * @hide
*/
- public void setAppId(int appId) {
+ public void setAppId(long appId) {
mAppId = appId;
}
@@ -113,6 +119,8 @@
* Set the application version
*
* @param appVersion - version of the app
+ *
+ * @hide
*/
public void setAppVersion(int appVersion) {
mAppVersion = appVersion;
@@ -131,6 +139,8 @@
* Set the read memory needed by the app
*
* @param neededReadMemBytes - readable Memory needed in bytes
+ *
+ * @hide
*/
public void setNeededReadMemBytes(int neededReadMemBytes) {
mNeededReadMemBytes = neededReadMemBytes;
@@ -150,6 +160,8 @@
*
* @param neededWriteMemBytes - writable memory needed by the
* app
+ *
+ * @hide
*/
public void setNeededWriteMemBytes(int neededWriteMemBytes) {
mNeededWriteMemBytes = neededWriteMemBytes;
@@ -169,6 +181,8 @@
*
* @param neededExecMemBytes - executable memory needed by the
* app
+ *
+ * @hide
*/
public void setNeededExecMemBytes(int neededExecMemBytes) {
mNeededExecMemBytes = neededExecMemBytes;
@@ -187,6 +201,8 @@
* set the sensors needed by this app
*
* @param neededSensors - all the sensors needed by this app
+ *
+ * @hide
*/
public void setNeededSensors(int[] neededSensors) {
mNeededSensors = neededSensors;
@@ -206,6 +222,8 @@
*
* @param outputEvents - the events that may be generated by
* this app
+ *
+ * @hide
*/
public void setOutputEvents(int[] outputEvents) {
mOutputEvents = outputEvents;
@@ -224,6 +242,8 @@
* set the context hub identifier
*
* @param contexthubId - system wide unique identifier
+ *
+ * @hide
*/
public void setContexthubId(int contexthubId) {
mContexthubId = contexthubId;
@@ -242,6 +262,8 @@
* set the handle for an app instance
*
* @param handle - handle to this instance
+ *
+ * @hide
*/
public void setHandle(int handle) {
mHandle = handle;
@@ -252,7 +274,7 @@
mPublisher = in.readString();
mName = in.readString();
- mAppId = in.readInt();
+ mAppId = in.readLong();
mAppVersion = in.readInt();
mNeededReadMemBytes = in.readInt();
mNeededWriteMemBytes = in.readInt();
@@ -274,7 +296,7 @@
public void writeToParcel(Parcel out, int flags) {
out.writeString(mPublisher);
out.writeString(mName);
- out.writeInt(mAppId);
+ out.writeLong(mAppId);
out.writeInt(mAppVersion);
out.writeInt(mContexthubId);
out.writeInt(mNeededReadMemBytes);
@@ -286,7 +308,6 @@
out.writeInt(mOutputEvents.length);
out.writeIntArray(mOutputEvents);
-
}
public static final Parcelable.Creator<NanoAppInstanceInfo> CREATOR
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 6b79a8a..9d53a00 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -295,9 +295,7 @@
boolean mLastShowInputRequested;
int mCandidatesVisibility;
CompletionInfo[] mCurCompletions;
-
- boolean mShowInputForced;
-
+
boolean mFullscreenApplied;
boolean mIsFullscreen;
View mExtractView;
@@ -422,7 +420,6 @@
boolean wasVis = isInputViewShown();
mShowInputFlags = 0;
mShowInputRequested = false;
- mShowInputForced = false;
doHideWindow();
clearInsetOfPreviousIme();
if (resultReceiver != null) {
@@ -439,8 +436,7 @@
public void showSoftInput(int flags, ResultReceiver resultReceiver) {
if (DEBUG) Log.v(TAG, "showSoftInput()");
boolean wasVis = isInputViewShown();
- mShowInputFlags = 0;
- if (onShowInputRequested(flags, false)) {
+ if (dispatchOnShowInputRequested(flags, false)) {
try {
showWindow(true);
} catch (BadTokenException e) {
@@ -817,8 +813,8 @@
mInitialized = false;
mWindowCreated = false;
mShowInputRequested = false;
- mShowInputForced = false;
-
+ mShowInputFlags = 0;
+
mThemeAttrs = obtainStyledAttributes(android.R.styleable.InputMethodService);
mRootView = mInflater.inflate(
com.android.internal.R.layout.input_method, null);
@@ -888,7 +884,7 @@
*/
@Override public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
-
+
boolean visible = mWindowVisible;
int showFlags = mShowInputFlags;
boolean showingInput = mShowInputRequested;
@@ -903,7 +899,7 @@
if (visible) {
if (showingInput) {
// If we were last showing the soft keyboard, try to do so again.
- if (onShowInputRequested(showFlags, true)) {
+ if (dispatchOnShowInputRequested(showFlags, true)) {
showWindow(true);
if (completions != null) {
mCurCompletions = completions;
@@ -1540,20 +1536,41 @@
return false;
}
}
- if ((flags&InputMethod.SHOW_FORCED) != 0) {
- mShowInputForced = true;
- }
return true;
}
-
+
+ /**
+ * A utility method to call {{@link #onShowInputRequested(int, boolean)}} and update internal
+ * states depending on its result. Since {@link #onShowInputRequested(int, boolean)} is
+ * exposed to IME authors as an overridable public method without {@code @CallSuper}, we have
+ * to have this method to ensure that those internal states are always updated no matter how
+ * {@link #onShowInputRequested(int, boolean)} is overridden by the IME author.
+ * @param flags Provides additional information about the show request,
+ * as per {@link InputMethod#showSoftInput InputMethod.showSoftInput()}.
+ * @param configChange This is true if we are re-showing due to a
+ * configuration change.
+ * @return Returns true to indicate that the window should be shown.
+ * @see #onShowInputRequested(int, boolean)
+ */
+ private boolean dispatchOnShowInputRequested(int flags, boolean configChange) {
+ final boolean result = onShowInputRequested(flags, configChange);
+ if (result) {
+ mShowInputFlags = flags;
+ } else {
+ mShowInputFlags = 0;
+ }
+ return result;
+ }
+
public void showWindow(boolean showInput) {
if (DEBUG) Log.v(TAG, "Showing window: showInput=" + showInput
+ " mShowInputRequested=" + mShowInputRequested
+ " mWindowAdded=" + mWindowAdded
+ " mWindowCreated=" + mWindowCreated
+ " mWindowVisible=" + mWindowVisible
- + " mInputStarted=" + mInputStarted);
-
+ + " mInputStarted=" + mInputStarted
+ + " mShowInputFlags=" + mShowInputFlags);
+
if (mInShowWindow) {
Log.w(TAG, "Re-entrance in to showWindow");
return;
@@ -2573,7 +2590,6 @@
p.println(" mShowInputRequested=" + mShowInputRequested
+ " mLastShowInputRequested=" + mLastShowInputRequested
- + " mShowInputForced=" + mShowInputForced
+ " mShowInputFlags=0x" + Integer.toHexString(mShowInputFlags));
p.println(" mCandidatesVisibility=" + mCandidatesVisibility
+ " mFullscreenApplied=" + mFullscreenApplied
diff --git a/core/java/android/net/ConnectivityMetricsEvent.aidl b/core/java/android/net/ConnectivityMetricsEvent.aidl
index da17561..a027d7c 100644
--- a/core/java/android/net/ConnectivityMetricsEvent.aidl
+++ b/core/java/android/net/ConnectivityMetricsEvent.aidl
@@ -17,3 +17,4 @@
package android.net;
parcelable ConnectivityMetricsEvent;
+parcelable ConnectivityMetricsEvent.Reference;
diff --git a/core/java/android/net/ConnectivityMetricsEvent.java b/core/java/android/net/ConnectivityMetricsEvent.java
index 098f1e6..b5d67d3 100644
--- a/core/java/android/net/ConnectivityMetricsEvent.java
+++ b/core/java/android/net/ConnectivityMetricsEvent.java
@@ -78,4 +78,42 @@
return String.format("ConnectivityMetricsEvent(%d, %d, %d)", timestamp,
componentTag, eventTag);
}
+
+ /** {@hide} */
+ public static class Reference implements Parcelable {
+
+ public long value;
+
+ public Reference(long ref) {
+ this.value = ref;
+ }
+
+ /** Implement the Parcelable interface */
+ public static final Parcelable.Creator<Reference> CREATOR
+ = new Parcelable.Creator<Reference> (){
+ public Reference createFromParcel(Parcel source) {
+ return new Reference(source.readLong());
+ }
+
+ public Reference[] newArray(int size) {
+ return new Reference[size];
+ }
+ };
+
+ /** Implement the Parcelable interface */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(value);
+ }
+
+ public void readFromParcel(Parcel in) {
+ value = in.readLong();
+ }
+ }
}
diff --git a/core/java/android/net/ConnectivityMetricsLogger.java b/core/java/android/net/ConnectivityMetricsLogger.java
index 3ef8050..eafb8ac 100644
--- a/core/java/android/net/ConnectivityMetricsLogger.java
+++ b/core/java/android/net/ConnectivityMetricsLogger.java
@@ -15,6 +15,7 @@
*/
package android.net;
+import android.os.Bundle;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -28,14 +29,24 @@
public static final String CONNECTIVITY_METRICS_LOGGER_SERVICE = "connectivity_metrics_logger";
// Component Tags
- public static final int COMPONENT_TAG_CONNECTIVITY = 1;
- public static final int COMPONENT_TAG_BLUETOOTH = 2;
- public static final int COMPONENT_TAG_WIFI = 3;
- public static final int COMPONENT_TAG_TELECOM = 4;
- public static final int COMPONENT_TAG_TELEPHONY = 5;
+ public static final int COMPONENT_TAG_CONNECTIVITY = 0;
+ public static final int COMPONENT_TAG_BLUETOOTH = 1;
+ public static final int COMPONENT_TAG_WIFI = 2;
+ public static final int COMPONENT_TAG_TELECOM = 3;
+ public static final int COMPONENT_TAG_TELEPHONY = 4;
+
+ public static final int NUMBER_OF_COMPONENTS = 5;
+
+ // Event Tag
+ public static final int TAG_SKIPPED_EVENTS = -1;
+
+ public static final String DATA_KEY_EVENTS_COUNT = "count";
private IConnectivityMetricsLogger mService;
+ private long mServiceUnblockedTimestampMillis = 0;
+ private int mNumSkippedEvents = 0;
+
public ConnectivityMetricsLogger() {
mService = IConnectivityMetricsLogger.Stub.asInterface(ServiceManager.getService(
CONNECTIVITY_METRICS_LOGGER_SERVICE));
@@ -46,12 +57,51 @@
if (DBG) {
Log.d(TAG, "logEvent(" + componentTag + "," + eventTag + ") Service not ready");
}
- } else {
- try {
- mService.logEvent(new ConnectivityMetricsEvent(timestamp, componentTag, eventTag, data));
- } catch (RemoteException e) {
- Log.e(TAG, "Error logging event " + e.getMessage());
+ return;
+ }
+
+ if (mServiceUnblockedTimestampMillis > 0) {
+ if (System.currentTimeMillis() < mServiceUnblockedTimestampMillis) {
+ // Service is throttling events.
+ // Don't send new events because they will be dropped.
+ mNumSkippedEvents++;
+ return;
}
}
+
+ ConnectivityMetricsEvent skippedEventsEvent = null;
+ if (mNumSkippedEvents > 0) {
+ // Log number of skipped events
+ Bundle b = new Bundle();
+ b.putInt(DATA_KEY_EVENTS_COUNT, mNumSkippedEvents);
+ skippedEventsEvent = new ConnectivityMetricsEvent(mServiceUnblockedTimestampMillis,
+ componentTag, TAG_SKIPPED_EVENTS, b);
+
+ mServiceUnblockedTimestampMillis = 0;
+ }
+
+ ConnectivityMetricsEvent event = new ConnectivityMetricsEvent(timestamp, componentTag,
+ eventTag, data);
+
+ try {
+ long result;
+ if (skippedEventsEvent == null) {
+ result = mService.logEvent(event);
+ } else {
+ result = mService.logEvents(new ConnectivityMetricsEvent[]
+ {skippedEventsEvent, event});
+ }
+
+ if (result == 0) {
+ mNumSkippedEvents = 0;
+ } else {
+ mNumSkippedEvents++;
+ if (result > 0) { // events are throttled
+ mServiceUnblockedTimestampMillis = result;
+ }
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error logging event " + e.getMessage());
+ }
}
}
diff --git a/core/java/android/net/DhcpResults.java b/core/java/android/net/DhcpResults.java
index 97bd5d2..8c5f603 100644
--- a/core/java/android/net/DhcpResults.java
+++ b/core/java/android/net/DhcpResults.java
@@ -40,6 +40,9 @@
public int leaseDuration;
+ /** Link MTU option. 0 means unset. */
+ public int mtu;
+
public DhcpResults() {
super();
}
@@ -57,19 +60,7 @@
serverAddress = source.serverAddress;
vendorInfo = source.vendorInfo;
leaseDuration = source.leaseDuration;
- }
- }
-
- /**
- * Updates the DHCP fields that need to be retained from
- * original DHCP request if the current renewal shows them
- * being empty.
- */
- public void updateFromDhcpRequest(DhcpResults orig) {
- if (orig == null) return;
- if (gateway == null) gateway = orig.gateway;
- if (dnsServers.size() == 0) {
- dnsServers.addAll(orig.dnsServers);
+ mtu = source.mtu;
}
}
@@ -89,6 +80,7 @@
super.clear();
vendorInfo = null;
leaseDuration = 0;
+ mtu = 0;
}
@Override
@@ -98,6 +90,7 @@
str.append(" DHCP server ").append(serverAddress);
str.append(" Vendor info ").append(vendorInfo);
str.append(" lease ").append(leaseDuration).append(" seconds");
+ if (mtu != 0) str.append(" MTU ").append(mtu);
return str.toString();
}
@@ -113,7 +106,8 @@
return super.equals((StaticIpConfiguration) obj) &&
Objects.equals(serverAddress, target.serverAddress) &&
Objects.equals(vendorInfo, target.vendorInfo) &&
- leaseDuration == target.leaseDuration;
+ leaseDuration == target.leaseDuration &&
+ mtu == target.mtu;
}
/** Implement the Parcelable interface */
@@ -134,6 +128,7 @@
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(leaseDuration);
+ dest.writeInt(mtu);
NetworkUtils.parcelInetAddress(dest, serverAddress, flags);
dest.writeString(vendorInfo);
}
@@ -141,6 +136,7 @@
private static void readFromParcel(DhcpResults dhcpResults, Parcel in) {
StaticIpConfiguration.readFromParcel(dhcpResults, in);
dhcpResults.leaseDuration = in.readInt();
+ dhcpResults.mtu = in.readInt();
dhcpResults.serverAddress = (Inet4Address) NetworkUtils.unparcelInetAddress(in);
dhcpResults.vendorInfo = in.readString();
}
diff --git a/core/java/android/net/IConnectivityMetricsLogger.aidl b/core/java/android/net/IConnectivityMetricsLogger.aidl
index 2778671..a83a019 100644
--- a/core/java/android/net/IConnectivityMetricsLogger.aidl
+++ b/core/java/android/net/IConnectivityMetricsLogger.aidl
@@ -16,15 +16,28 @@
package android.net;
+import android.app.PendingIntent;
import android.net.ConnectivityMetricsEvent;
-import android.net.IConnectivityMetricsLoggerSubscriber;
/** {@hide} */
interface IConnectivityMetricsLogger {
- void logEvent(in ConnectivityMetricsEvent event);
- void logEvents(in ConnectivityMetricsEvent[] events);
+ /**
+ * @return 0 on success
+ * <0 if error happened
+ * >0 timestamp after which new events will be accepted
+ */
+ long logEvent(in ConnectivityMetricsEvent event);
+ long logEvents(in ConnectivityMetricsEvent[] events);
- boolean subscribe(in IConnectivityMetricsLoggerSubscriber subscriber);
- void unsubscribe(in IConnectivityMetricsLoggerSubscriber subscriber);
+ /**
+ * @param reference of the last event previously returned. The function will return
+ * events following it.
+ * If 0 then all events will be returned.
+ * After the function call it will contain reference of the last event.
+ */
+ ConnectivityMetricsEvent[] getEvents(inout ConnectivityMetricsEvent.Reference reference);
+
+ boolean register(in PendingIntent newEventsIntent);
+ void unregister(in PendingIntent newEventsIntent);
}
diff --git a/core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl b/core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl
deleted file mode 100644
index a2c62cd..0000000
--- a/core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2016 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.net;
-
-import android.net.ConnectivityMetricsEvent;
-
-/** {@hide} */
-oneway interface IConnectivityMetricsLoggerSubscriber {
-
- void onEvents(in ConnectivityMetricsEvent[] events);
-}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 8e2dd6b..c452837 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -448,19 +448,41 @@
public abstract Timer getForegroundActivityTimer();
public abstract Timer getBluetoothScanTimer();
- // Time this uid has any processes in the top state.
+ // Note: the following times are disjoint. They can be added together to find the
+ // total time a uid has had any processes running at all.
+
+ /**
+ * Time this uid has any processes in the top state (or above such as persistent).
+ */
public static final int PROCESS_STATE_TOP = 0;
- // Time this uid has any process with a started out bound foreground service.
+ /**
+ * Time this uid has any process with a started out bound foreground service, but
+ * none in the "top" state.
+ */
public static final int PROCESS_STATE_FOREGROUND_SERVICE = 1;
- // Time this uid has any process that is top while the device is sleeping.
+ /**
+ * Time this uid has any process that is top while the device is sleeping, but none
+ * in the "foreground service" or better state.
+ */
public static final int PROCESS_STATE_TOP_SLEEPING = 2;
- // Time this uid has any process in an active foreground state.
+ /**
+ * Time this uid has any process in an active foreground state, but none in the
+ * "top sleeping" or better state.
+ */
public static final int PROCESS_STATE_FOREGROUND = 3;
- // Time this uid has any process in an active background state.
+ /**
+ * Time this uid has any process in an active background state, but none in the
+ * "foreground" or better state.
+ */
public static final int PROCESS_STATE_BACKGROUND = 4;
- // Time this uid has any processes running at all.
+ /**
+ * Time this uid has any processes that are sitting around cached, not in one of the
+ * other active states.
+ */
public static final int PROCESS_STATE_CACHED = 5;
- // Total number of process states we track.
+ /**
+ * Total number of process states we track.
+ */
public static final int NUM_PROCESS_STATE = 6;
static final String[] PROCESS_STATE_NAMES = {
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 05dd48b..1128074 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -208,6 +208,18 @@
}
/**
+ * Removes any entry with the given key from the mapping of this Bundle.
+ *
+ * @param key a String key
+ */
+ public void remove(String key) {
+ super.remove(key);
+ if ((mFlags & FLAG_HAS_FDS) != 0) {
+ mFlags &= ~FLAG_HAS_FDS_KNOWN;
+ }
+ }
+
+ /**
* Inserts all mappings from the given Bundle into this Bundle.
*
* @param bundle a Bundle
@@ -288,6 +300,8 @@
if (fdFound) {
mFlags |= FLAG_HAS_FDS;
+ } else {
+ mFlags &= ~FLAG_HAS_FDS;
}
mFlags |= FLAG_HAS_FDS_KNOWN;
}
@@ -315,6 +329,8 @@
mMap.removeAt(i);
}
}
+ mFlags |= FLAG_HAS_FDS_KNOWN;
+ mFlags &= ~FLAG_HAS_FDS;
}
/**
diff --git a/core/java/android/os/HardwarePropertiesManager.java b/core/java/android/os/HardwarePropertiesManager.java
index f13e5b5..9d362d6 100644
--- a/core/java/android/os/HardwarePropertiesManager.java
+++ b/core/java/android/os/HardwarePropertiesManager.java
@@ -48,7 +48,8 @@
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({
- TEMPERATURE_CURRENT, TEMPERATURE_THROTTLING, TEMPERATURE_SHUTDOWN
+ TEMPERATURE_CURRENT, TEMPERATURE_THROTTLING, TEMPERATURE_SHUTDOWN,
+ TEMPERATURE_THROTTLING_BELOW_VR_MIN
})
public @interface TemperatureSource {}
@@ -77,6 +78,12 @@
/** Get shutdown temperature threshold. */
public static final int TEMPERATURE_SHUTDOWN = 2;
+ /**
+ * Get throttling temperature threshold above which minimum clockrates for VR mode will not be
+ * met.
+ */
+ public static final int TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3;
+
/** Undefined temperature constant. */
public static final float UNDEFINED_TEMPERATURE = -Float.MAX_VALUE;
@@ -96,7 +103,8 @@
* {@link #DEVICE_TEMPERATURE_GPU}, {@link #DEVICE_TEMPERATURE_BATTERY} or {@link
* #DEVICE_TEMPERATURE_SKIN}.
* @param source source of requested device temperature, one of {@link #TEMPERATURE_CURRENT},
- * {@link #TEMPERATURE_THROTTLING} or {@link #TEMPERATURE_SHUTDOWN}.
+ * {@link #TEMPERATURE_THROTTLING}, {@link #TEMPERATURE_THROTTLING_BELOW_VR_MIN} or
+ * {@link #TEMPERATURE_SHUTDOWN}.
* @return an array of requested float device temperatures. Temperature equals to
* {@link #UNDEFINED_TEMPERATURE} if undefined.
* Empty if platform doesn't provide the queried temperature.
@@ -115,6 +123,7 @@
case TEMPERATURE_CURRENT:
case TEMPERATURE_THROTTLING:
case TEMPERATURE_SHUTDOWN:
+ case TEMPERATURE_THROTTLING_BELOW_VR_MIN:
try {
return mService.getDeviceTemperatures(mContext.getOpPackageName(), type,
source);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index a0a16f1..92edc62 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -221,7 +221,7 @@
/**
* Wake lock level: Enables Sustained Performance Mode.
* <p>
- * This is used by Gaming and VR applications to ensure the device provides
+ * This is used by Gaming and VR applications to ensure the device
* will provide consistent performance over a large amount of time.
* </p>
*/
@@ -1031,6 +1031,16 @@
}
/**
+ * Returns True if the device supports Sustained Performance Mode.
+ * Applications Should check if the device supports this mode, before
+ * using {@link #SUSTAINED_PERFORMANCE_WAKE_LOCK}.
+ */
+ public boolean isSustainedPerformanceModeSupported() {
+ return mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_sustainedPerformanceModeSupported);
+ }
+
+ /**
* Intent that is broadcast when the state of {@link #isPowerSaveMode()} changes.
* This broadcast is only sent to registered receivers.
*/
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index d41bc07..b1cad05 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -1184,10 +1184,9 @@
/**
* Called when the Preference hierarchy has been attached to the
- * {@link PreferenceActivity} or {@link PreferenceFragment}. This can
- * also be called when this Preference has been attached to a group
- * that was already attached to the {@link PreferenceActivity} or
- * {@link PreferenceFragment}.
+ * {@link PreferenceActivity}. This can also be called when this
+ * Preference has been attached to a group that was already attached
+ * to the {@link PreferenceActivity}.
*/
protected void onAttachedToActivity() {
// At this point, the hierarchy that this preference is in is connected
@@ -1195,16 +1194,6 @@
registerDependency();
}
- /**
- * Called when the Preference hierarchy has been detached from the
- * {@link PreferenceActivity} or {@link PreferenceFragment}. This can
- * also be called when this Preference has been removed from a group
- * that was already attached to the {@link PreferenceActivity} or
- * {@link PreferenceFragment}.
- */
- protected void onDetachedFromActivity() {
- }
-
private void registerDependency() {
if (TextUtils.isEmpty(mDependencyKey)) return;
diff --git a/core/java/android/preference/PreferenceGroup.java b/core/java/android/preference/PreferenceGroup.java
index 13c3661..f17506b 100644
--- a/core/java/android/preference/PreferenceGroup.java
+++ b/core/java/android/preference/PreferenceGroup.java
@@ -186,11 +186,7 @@
private boolean removePreferenceInt(Preference preference) {
synchronized(this) {
preference.onPrepareForRemoval();
- boolean success = mPreferenceList.remove(preference);
- if (mAttachedToActivity) {
- preference.onDetachedFromActivity();
- }
- return success;
+ return mPreferenceList.remove(preference);
}
}
@@ -266,7 +262,7 @@
protected boolean isOnSameScreenAsChildren() {
return true;
}
-
+
@Override
protected void onAttachedToActivity() {
super.onAttachedToActivity();
@@ -283,17 +279,11 @@
}
@Override
- protected void onDetachedFromActivity() {
- super.onDetachedFromActivity();
-
+ protected void onPrepareForRemoval() {
+ super.onPrepareForRemoval();
+
// We won't be attached to the activity anymore
mAttachedToActivity = false;
-
- // Dispatch to all contained preferences
- final int preferenceCount = getPreferenceCount();
- for (int i = 0; i < preferenceCount; i++) {
- getPreference(i).onDetachedFromActivity();
- }
}
@Override
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index 73174e3..1a6b06f 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -519,9 +519,6 @@
*/
boolean setPreferences(PreferenceScreen preferenceScreen) {
if (preferenceScreen != mPreferenceScreen) {
- if (mPreferenceScreen != null) {
- mPreferenceScreen.onDetachedFromActivity();
- }
mPreferenceScreen = preferenceScreen;
return true;
}
@@ -830,11 +827,7 @@
*/
void dispatchActivityDestroy() {
List<OnActivityDestroyListener> list = null;
-
- if (mPreferenceScreen != null) {
- mPreferenceScreen.onDetachedFromActivity();
- mPreferenceScreen = null;
- }
+
synchronized (this) {
if (mActivityDestroyListeners != null) {
list = new ArrayList<OnActivityDestroyListener>(mActivityDestroyListeners);
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index e9c196d..721c94e 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -20,6 +20,7 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.StringRes;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources.NotFoundException;
@@ -31,6 +32,7 @@
import android.util.Log;
import com.android.internal.R;
+import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -49,7 +51,7 @@
@IntDef(flag = true, value = {
COLOR_MODE_MONOCHROME, COLOR_MODE_COLOR
})
- public @interface ColorMode {
+ @interface ColorMode {
}
/** Color mode: Monochrome color scheme, for example one color is used. */
public static final int COLOR_MODE_MONOCHROME = 1 << 0;
@@ -64,7 +66,7 @@
@IntDef(flag = true, value = {
DUPLEX_MODE_NONE, DUPLEX_MODE_LONG_EDGE, DUPLEX_MODE_SHORT_EDGE
})
- public @interface DuplexMode {
+ @interface DuplexMode {
}
/** Duplex mode: No duplexing. */
public static final int DUPLEX_MODE_NONE = 1 << 0;
@@ -76,23 +78,29 @@
private static final int VALID_DUPLEX_MODES =
DUPLEX_MODE_NONE | DUPLEX_MODE_LONG_EDGE | DUPLEX_MODE_SHORT_EDGE;
- private MediaSize mMediaSize;
- private Resolution mResolution;
- private Margins mMinMargins;
+ private @Nullable MediaSize mMediaSize;
+ private @Nullable Resolution mResolution;
+ private @Nullable Margins mMinMargins;
- private int mColorMode;
- private int mDuplexMode;
+ private @IntRange(from = 0) int mColorMode;
+ private @IntRange(from = 0) int mDuplexMode;
PrintAttributes() {
/* hide constructor */
}
private PrintAttributes(@NonNull Parcel parcel) {
- mMediaSize = (parcel.readInt() == 1) ? MediaSize.createFromParcel(parcel) : null;
- mResolution = (parcel.readInt() == 1) ? Resolution.createFromParcel(parcel) : null;
- mMinMargins = (parcel.readInt() == 1) ? Margins.createFromParcel(parcel) : null;
+ mMediaSize = (parcel.readInt() == 1) ? MediaSize.createFromParcel(parcel) : null;
+ mResolution = (parcel.readInt() == 1) ? Resolution.createFromParcel(parcel) : null;
+ mMinMargins = (parcel.readInt() == 1) ? Margins.createFromParcel(parcel) : null;
mColorMode = parcel.readInt();
+ if (mColorMode != 0) {
+ enforceValidColorMode(mColorMode);
+ }
mDuplexMode = parcel.readInt();
+ if (mDuplexMode != 0) {
+ enforceValidDuplexMode(mDuplexMode);
+ }
}
/**
@@ -179,7 +187,7 @@
* @see #COLOR_MODE_COLOR
* @see #COLOR_MODE_MONOCHROME
*/
- public @ColorMode int getColorMode() {
+ public @IntRange(from = 0) int getColorMode() {
return mColorMode;
}
@@ -214,13 +222,13 @@
/**
* Gets the duplex mode.
*
- * @return The duplex mode.
+ * @return The duplex mode or zero if not set.
*
* @see #DUPLEX_MODE_NONE
* @see #DUPLEX_MODE_LONG_EDGE
* @see #DUPLEX_MODE_SHORT_EDGE
*/
- public @DuplexMode int getDuplexMode() {
+ public @IntRange(from = 0) int getDuplexMode() {
return mDuplexMode;
}
@@ -448,7 +456,7 @@
private static final String LOG_TAG = "MediaSize";
private static final Map<String, MediaSize> sIdToMediaSizeMap =
- new ArrayMap<String, MediaSize>();
+ new ArrayMap<>();
/**
* Unknown media size in portrait mode.
@@ -781,15 +789,15 @@
new MediaSize("JPN_YOU4", "android",
R.string.mediasize_japanese_you4, 4134, 9252);
- private final String mId;
+ private final @NonNull String mId;
/**@hide */
- public final String mLabel;
+ public final @NonNull String mLabel;
/**@hide */
- public final String mPackageName;
+ public final @Nullable String mPackageName;
/**@hide */
- public final int mLabelResId;
- private final int mWidthMils;
- private final int mHeightMils;
+ public final @StringRes int mLabelResId;
+ private final @IntRange(from = 1) int mWidthMils;
+ private final @IntRange(from = 1) int mHeightMils;
/**
* Creates a new instance.
@@ -808,29 +816,7 @@
*/
public MediaSize(String id, String packageName, int labelResId,
int widthMils, int heightMils) {
- if (TextUtils.isEmpty(id)) {
- throw new IllegalArgumentException("id cannot be empty.");
- }
- if (TextUtils.isEmpty(packageName)) {
- throw new IllegalArgumentException("packageName cannot be empty.");
- }
- if (labelResId <= 0) {
- throw new IllegalArgumentException("labelResId must be greater than zero.");
- }
- if (widthMils <= 0) {
- throw new IllegalArgumentException("widthMils "
- + "cannot be less than or equal to zero.");
- }
- if (heightMils <= 0) {
- throw new IllegalArgumentException("heightMils "
- + "cannot be less than or euqual to zero.");
- }
- mPackageName = packageName;
- mId = id;
- mLabelResId = labelResId;
- mWidthMils = widthMils;
- mHeightMils = heightMils;
- mLabel = null;
+ this(id, null, packageName, widthMils, heightMils, labelResId);
// Build this mapping only for predefined media sizes.
sIdToMediaSizeMap.put(mId, this);
@@ -851,26 +837,7 @@
*/
public MediaSize(@NonNull String id, @NonNull String label,
@IntRange(from = 1) int widthMils, @IntRange(from = 1) int heightMils) {
- if (TextUtils.isEmpty(id)) {
- throw new IllegalArgumentException("id cannot be empty.");
- }
- if (TextUtils.isEmpty(label)) {
- throw new IllegalArgumentException("label cannot be empty.");
- }
- if (widthMils <= 0) {
- throw new IllegalArgumentException("widthMils "
- + "cannot be less than or equal to zero.");
- }
- if (heightMils <= 0) {
- throw new IllegalArgumentException("heightMils "
- + "cannot be less than or euqual to zero.");
- }
- mId = id;
- mLabel = label;
- mWidthMils = widthMils;
- mHeightMils = heightMils;
- mLabelResId = 0;
- mPackageName = null;
+ this(id, label, null, widthMils, heightMils, 0);
}
/**
@@ -890,15 +857,37 @@
return definedMediaSizes;
}
- /** @hide */
- public MediaSize(String id, String label, String packageName,
- int widthMils, int heightMils, int labelResId) {
+ /**
+ * Creates a new instance.
+ *
+ * @param id The unique media size id. It is unique amongst other media sizes
+ * supported by the printer.
+ * @param label The <strong>localized</strong> human readable label.
+ * @param packageName The name of the creating package.
+ * @param widthMils The width in mils (thousands of an inch).
+ * @param heightMils The height in mils (thousands of an inch).
+ * @param labelResId The resource if of a human readable label.
+ *
+ * @throws IllegalArgumentException If the id is empty or the label is unset
+ * or the widthMils is less than or equal to zero or the heightMils is less
+ * than or equal to zero.
+ *
+ * @hide
+ */
+ public MediaSize(String id, String label, String packageName, int widthMils, int heightMils,
+ int labelResId) {
mPackageName = packageName;
- mId = id;
+ mId = Preconditions.checkStringNotEmpty(id, "id cannot be empty.");
mLabelResId = labelResId;
- mWidthMils = widthMils;
- mHeightMils = heightMils;
+ mWidthMils = Preconditions.checkArgumentPositive(widthMils, "widthMils cannot be " +
+ "less than or equal to zero.");
+ mHeightMils = Preconditions.checkArgumentPositive(heightMils, "heightMils cannot be " +
+ "less than or equal to zero.");
mLabel = label;
+
+ // The label has to be either a string ot a StringRes
+ Preconditions.checkArgument(!TextUtils.isEmpty(label) !=
+ (!TextUtils.isEmpty(packageName) && labelResId != 0), "label cannot be empty.");
}
/**
@@ -926,10 +915,7 @@
try {
return packageManager.getResourcesForApplication(
mPackageName).getString(mLabelResId);
- } catch (NotFoundException nfe) {
- Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
- + " from package " + mPackageName);
- } catch (NameNotFoundException nnfee) {
+ } catch (NotFoundException | NameNotFoundException e) {
Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
+ " from package " + mPackageName);
}
@@ -1084,10 +1070,10 @@
* the one with 300 DPI resolution.
*/
public static final class Resolution {
- private final String mId;
- private final String mLabel;
- private final int mHorizontalDpi;
- private final int mVerticalDpi;
+ private final @NonNull String mId;
+ private final @NonNull String mLabel;
+ private final @IntRange(from = 1) int mHorizontalDpi;
+ private final @IntRange(from = 1) int mVerticalDpi;
/**
* Creates a new instance.
@@ -1244,8 +1230,7 @@
* @param rightMils The right margin in mils (thousands of an inch).
* @param bottomMils The bottom margin in mils (thousands of an inch).
*/
- public Margins(@IntRange(from = 0) int leftMils, @IntRange(from = 0) int topMils,
- @IntRange(from = 0) int rightMils, @IntRange(from = 0) int bottomMils) {
+ public Margins(int leftMils, int topMils, int rightMils, int bottomMils) {
mTopMils = topMils;
mLeftMils = leftMils;
mRightMils = rightMils;
@@ -1257,7 +1242,7 @@
*
* @return The left margin.
*/
- public @IntRange(from = 0) int getLeftMils() {
+ public int getLeftMils() {
return mLeftMils;
}
@@ -1266,7 +1251,7 @@
*
* @return The top margin.
*/
- public @IntRange(from = 0) int getTopMils() {
+ public int getTopMils() {
return mTopMils;
}
@@ -1275,7 +1260,7 @@
*
* @return The right margin.
*/
- public @IntRange(from = 0) int getRightMils() {
+ public int getRightMils() {
return mRightMils;
}
@@ -1284,7 +1269,7 @@
*
* @return The bottom margin.
*/
- public @IntRange(from = 0) int getBottomMils() {
+ public int getBottomMils() {
return mBottomMils;
}
diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java
index db3b6f4..bec6f29 100644
--- a/core/java/android/print/PrintDocumentInfo.java
+++ b/core/java/android/print/PrintDocumentInfo.java
@@ -22,6 +22,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -114,8 +115,8 @@
*/
public static final int CONTENT_TYPE_PHOTO = 1;
- private String mName;
- private int mPageCount;
+ private @NonNull String mName;
+ private @IntRange(from = -1) int mPageCount;
private int mContentType;
private long mDataSize;
@@ -144,10 +145,11 @@
* @param parcel Data from which to initialize.
*/
private PrintDocumentInfo(Parcel parcel) {
- mName = parcel.readString();
+ mName = Preconditions.checkStringNotEmpty(parcel.readString());
mPageCount = parcel.readInt();
+ Preconditions.checkArgument(mPageCount == PAGE_COUNT_UNKNOWN || mPageCount > 0);
mContentType = parcel.readInt();
- mDataSize = parcel.readLong();
+ mDataSize = Preconditions.checkArgumentNonnegative(parcel.readLong());
}
/**
@@ -180,7 +182,7 @@
* @see #CONTENT_TYPE_DOCUMENT
* @see #CONTENT_TYPE_PHOTO
*/
- public @ContentType int getContentType() {
+ public int getContentType() {
return mContentType;
}
@@ -262,13 +264,13 @@
builder.append("PrintDocumentInfo{");
builder.append("name=").append(mName);
builder.append(", pageCount=").append(mPageCount);
- builder.append(", contentType=").append(contentTyepToString(mContentType));
+ builder.append(", contentType=").append(contentTypeToString(mContentType));
builder.append(", dataSize=").append(mDataSize);
builder.append("}");
return builder.toString();
}
- private String contentTyepToString(int contentType) {
+ private String contentTypeToString(int contentType) {
switch (contentType) {
case CONTENT_TYPE_DOCUMENT: {
return "CONTENT_TYPE_DOCUMENT";
diff --git a/core/java/android/print/PrinterCapabilitiesInfo.java b/core/java/android/print/PrinterCapabilitiesInfo.java
index d13879b..01c23f6 100644
--- a/core/java/android/print/PrinterCapabilitiesInfo.java
+++ b/core/java/android/print/PrinterCapabilitiesInfo.java
@@ -24,11 +24,13 @@
import android.print.PrintAttributes.Margins;
import android.print.PrintAttributes.MediaSize;
import android.print.PrintAttributes.Resolution;
+import com.android.internal.util.Preconditions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.function.IntConsumer;
/**
* This class represents the capabilities of a printer. Instances
@@ -55,9 +57,9 @@
private static final Margins DEFAULT_MARGINS = new Margins(0, 0, 0, 0);
- private Margins mMinMargins = DEFAULT_MARGINS;
- private List<MediaSize> mMediaSizes;
- private List<Resolution> mResolutions;
+ private @NonNull Margins mMinMargins = DEFAULT_MARGINS;
+ private @NonNull List<MediaSize> mMediaSizes;
+ private @NonNull List<Resolution> mResolutions;
private int mColorModes;
private int mDuplexModes;
@@ -205,15 +207,37 @@
return builder.build();
}
+ /**
+ * Call enforceSingle for each bit in the mask.
+ *
+ * @param mask The mask
+ * @param enforceSingle The function to call
+ */
+ private static void enforceValidMask(int mask, IntConsumer enforceSingle) {
+ int current = mask;
+ while (current > 0) {
+ final int currentMode = (1 << Integer.numberOfTrailingZeros(current));
+ current &= ~currentMode;
+ enforceSingle.accept(currentMode);
+ }
+ }
+
private PrinterCapabilitiesInfo(Parcel parcel) {
- mMinMargins = readMargins(parcel);
+ mMinMargins = Preconditions.checkNotNull(readMargins(parcel));
readMediaSizes(parcel);
readResolutions(parcel);
mColorModes = parcel.readInt();
+ enforceValidMask(mColorModes,
+ (currentMode) -> PrintAttributes.enforceValidColorMode(currentMode));
+
mDuplexModes = parcel.readInt();
+ enforceValidMask(mDuplexModes,
+ (currentMode) -> PrintAttributes.enforceValidDuplexMode(currentMode));
readDefaults(parcel);
+ Preconditions.checkArgument(mMediaSizes.size() > mDefaults[PROPERTY_MEDIA_SIZE]);
+ Preconditions.checkArgument(mResolutions.size() > mDefaults[PROPERTY_RESOLUTION]);
}
@Override
@@ -537,12 +561,8 @@
*/
public @NonNull Builder setColorModes(@ColorMode int colorModes,
@ColorMode int defaultColorMode) {
- int currentModes = colorModes;
- while (currentModes > 0) {
- final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes));
- currentModes &= ~currentMode;
- PrintAttributes.enforceValidColorMode(currentMode);
- }
+ enforceValidMask(colorModes,
+ (currentMode) -> PrintAttributes.enforceValidColorMode(currentMode));
PrintAttributes.enforceValidColorMode(defaultColorMode);
mPrototype.mColorModes = colorModes;
mPrototype.mDefaults[PROPERTY_COLOR_MODE] = defaultColorMode;
@@ -568,12 +588,8 @@
*/
public @NonNull Builder setDuplexModes(@DuplexMode int duplexModes,
@DuplexMode int defaultDuplexMode) {
- int currentModes = duplexModes;
- while (currentModes > 0) {
- final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes));
- currentModes &= ~currentMode;
- PrintAttributes.enforceValidDuplexMode(currentMode);
- }
+ enforceValidMask(duplexModes,
+ (currentMode) -> PrintAttributes.enforceValidDuplexMode(currentMode));
PrintAttributes.enforceValidDuplexMode(defaultDuplexMode);
mPrototype.mDuplexModes = duplexModes;
mPrototype.mDefaults[PROPERTY_DUPLEX_MODE] = defaultDuplexMode;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ebecfdb..f4d63ac 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1569,9 +1569,8 @@
* @return true if the calling app can draw on top of other apps, false otherwise.
*/
public static boolean canDrawOverlays(Context context) {
- int uid = Binder.getCallingUid();
- return Settings.isCallingPackageAllowedToDrawOverlays(context, uid, Settings
- .getPackageNameForUid(context, uid), false);
+ return Settings.isCallingPackageAllowedToDrawOverlays(context, Process.myUid(),
+ context.getOpPackageName(), false);
}
/**
@@ -3885,9 +3884,8 @@
* @return true if the calling app can write to system settings, false otherwise
*/
public static boolean canWrite(Context context) {
- int uid = Binder.getCallingUid();
- return isCallingPackageAllowedToWriteSettings(context, uid, getPackageNameForUid(
- context, uid), false);
+ return isCallingPackageAllowedToWriteSettings(context, Process.myUid(),
+ context.getOpPackageName(), false);
}
}
@@ -3991,6 +3989,7 @@
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SAVED_STATE);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED);
+ MOVED_TO_GLOBAL.add(Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_ENHANCED_AUTO_JOIN);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_NETWORK_SHOW_RSSI);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_ON);
@@ -7258,6 +7257,14 @@
"wifi_suspend_optimizations_enabled";
/**
+ * Setting to enable verbose logging in Wi-Fi; disabled by default, and setting to 1
+ * will enable it. In the future, additional values may be supported.
+ * @hide
+ */
+ public static final String WIFI_VERBOSE_LOGGING_ENABLED =
+ "wifi_verbose_logging_enabled";
+
+ /**
* The maximum number of times we will retry a connection to an access
* point for which we have failed in acquiring an IP address from DHCP.
* A value of N means that we will make N+1 connection attempts in all.
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 7af0b05..0557d13 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -35,7 +35,6 @@
import android.view.ActionMode;
import android.view.Display;
import android.view.KeyEvent;
-import android.view.KeyboardShortcutGroup;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index d9227ce..78d3b7b 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -606,7 +606,6 @@
private static final int SIGNATURE_ECDSA_WITH_SHA256 = 0x0201;
private static final int SIGNATURE_ECDSA_WITH_SHA512 = 0x0202;
private static final int SIGNATURE_DSA_WITH_SHA256 = 0x0301;
- private static final int SIGNATURE_DSA_WITH_SHA512 = 0x0302;
private static final int CONTENT_DIGEST_CHUNKED_SHA256 = 1;
private static final int CONTENT_DIGEST_CHUNKED_SHA512 = 2;
@@ -620,7 +619,6 @@
case SIGNATURE_ECDSA_WITH_SHA256:
case SIGNATURE_ECDSA_WITH_SHA512:
case SIGNATURE_DSA_WITH_SHA256:
- case SIGNATURE_DSA_WITH_SHA512:
return true;
default:
return false;
@@ -670,7 +668,6 @@
case SIGNATURE_RSA_PSS_WITH_SHA512:
case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512:
case SIGNATURE_ECDSA_WITH_SHA512:
- case SIGNATURE_DSA_WITH_SHA512:
return CONTENT_DIGEST_CHUNKED_SHA512;
default:
throw new IllegalArgumentException(
@@ -714,7 +711,6 @@
case SIGNATURE_ECDSA_WITH_SHA512:
return "EC";
case SIGNATURE_DSA_WITH_SHA256:
- case SIGNATURE_DSA_WITH_SHA512:
return "DSA";
default:
throw new IllegalArgumentException(
@@ -746,8 +742,6 @@
return Pair.create("SHA512withECDSA", null);
case SIGNATURE_DSA_WITH_SHA256:
return Pair.create("SHA256withDSA", null);
- case SIGNATURE_DSA_WITH_SHA512:
- return Pair.create("SHA512withDSA", null);
default:
throw new IllegalArgumentException(
"Unknown signature algorithm: 0x"
diff --git a/core/java/android/view/ContextThemeWrapper.java b/core/java/android/view/ContextThemeWrapper.java
index 4888877..86318e9 100644
--- a/core/java/android/view/ContextThemeWrapper.java
+++ b/core/java/android/view/ContextThemeWrapper.java
@@ -101,6 +101,15 @@
mOverrideConfiguration = new Configuration(overrideConfiguration);
}
+ /**
+ * Used by ActivityThread to apply the overridden configuration to onConfigurationChange
+ * callbacks.
+ * @hide
+ */
+ public Configuration getOverrideConfiguration() {
+ return mOverrideConfiguration;
+ }
+
@Override
public AssetManager getAssets() {
// Ensure we're returning assets with the correct configuration.
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 7af4a1f..4ba97d5 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -180,7 +180,12 @@
// caller must call setNewConfiguration() sometime later.
Configuration updateOrientationFromAppTokens(in Configuration currentConfig,
IBinder freezeThisOneIfNeeded);
- void setNewConfiguration(in Configuration config);
+ // Notify window manager of the new configuration. Returns an array of stack ids that's
+ // affected by the update, ActivityManager should resize these stacks.
+ int[] setNewConfiguration(in Configuration config);
+
+ // Retrieves the new bounds after the configuration update evaluated by window manager.
+ Rect getBoundsForNewConfiguration(int stackId);
void startFreezingScreen(int exitAnim, int enterAnim);
void stopFreezingScreen();
@@ -400,4 +405,14 @@
* @hide
*/
void registerShortcutKey(in long shortcutCode, IShortcutService keySubscriber);
+
+ /**
+ * Create the input consumer for wallpaper events.
+ */
+ void createWallpaperInputConsumer(out InputChannel inputChannel);
+
+ /**
+ * Remove the input consumer for wallpaper events.
+ */
+ void removeWallpaperInputConsumer();
}
diff --git a/core/java/android/view/KeyboardShortcutInfo.java b/core/java/android/view/KeyboardShortcutInfo.java
index c2bd347..eee925d 100644
--- a/core/java/android/view/KeyboardShortcutInfo.java
+++ b/core/java/android/view/KeyboardShortcutInfo.java
@@ -51,7 +51,7 @@
mLabel = label;
mIcon = icon;
mBaseCharacter = MIN_VALUE;
- checkArgument(keycode > KeyEvent.KEYCODE_UNKNOWN && keycode <= KeyEvent.getMaxKeyCode());
+ checkArgument(keycode >= KeyEvent.KEYCODE_UNKNOWN && keycode <= KeyEvent.getMaxKeyCode());
mKeycode = keycode;
mModifiers = modifiers;
}
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index a19254f..ab4cbcf 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -307,18 +307,22 @@
*
* Deep copies the data into native to simplify reference ownership.
*/
- public boolean setOutline(Outline outline) {
+ public boolean setOutline(@Nullable Outline outline) {
if (outline == null) {
return nSetOutlineNone(mNativeRenderNode);
- } else if (outline.isEmpty()) {
- return nSetOutlineEmpty(mNativeRenderNode);
- } else if (outline.mRect != null) {
- return nSetOutlineRoundRect(mNativeRenderNode, outline.mRect.left, outline.mRect.top,
- outline.mRect.right, outline.mRect.bottom, outline.mRadius, outline.mAlpha);
- } else if (outline.mPath != null) {
- return nSetOutlineConvexPath(mNativeRenderNode, outline.mPath.mNativePath,
- outline.mAlpha);
}
+
+ switch(outline.mMode) {
+ case Outline.MODE_EMPTY:
+ return nSetOutlineEmpty(mNativeRenderNode);
+ case Outline.MODE_ROUND_RECT:
+ return nSetOutlineRoundRect(mNativeRenderNode, outline.mRect.left, outline.mRect.top,
+ outline.mRect.right, outline.mRect.bottom, outline.mRadius, outline.mAlpha);
+ case Outline.MODE_CONVEX_PATH:
+ return nSetOutlineConvexPath(mNativeRenderNode, outline.mPath.mNativePath,
+ outline.mAlpha);
+ }
+
throw new IllegalArgumentException("Unrecognized outline?");
}
@@ -763,6 +767,16 @@
return nGetDebugSize(mNativeRenderNode);
}
+ /**
+ * Called by native when the passed displaylist is removed from the draw tree
+ */
+ void onRenderNodeDetached() {
+ discardDisplayList();
+ if (mOwningView != null) {
+ mOwningView.onRenderNodeDetached(this);
+ }
+ }
+
///////////////////////////////////////////////////////////////////////////
// Animations
///////////////////////////////////////////////////////////////////////////
@@ -795,7 +809,9 @@
// Native methods
///////////////////////////////////////////////////////////////////////////
- private static native long nCreate(String name);
+ // Intentionally not static because it acquires a reference to 'this'
+ private native long nCreate(String name);
+
private static native void nDestroyRenderNode(long renderNode);
private static native void nSetDisplayList(long renderNode, long newData);
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index 37e4000..7cd161c 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -145,13 +145,6 @@
private int mSpanSlop;
private int mMinSpan;
- // Bounds for recently seen values
- private float mTouchUpper;
- private float mTouchLower;
- private float mTouchHistoryLastAccepted;
- private int mTouchHistoryDirection;
- private long mTouchHistoryLastAcceptedTime;
- private int mTouchMinMajor;
private final Handler mHandler;
private float mAnchoredScaleStartX;
@@ -207,8 +200,6 @@
mSpanSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2;
final Resources res = context.getResources();
- mTouchMinMajor = res.getDimensionPixelSize(
- com.android.internal.R.dimen.config_minScalingTouchMajor);
mMinSpan = res.getDimensionPixelSize(com.android.internal.R.dimen.config_minScalingSpan);
mHandler = handler;
// Quick scale is enabled by default after JB_MR2
@@ -223,77 +214,6 @@
}
/**
- * The touchMajor/touchMinor elements of a MotionEvent can flutter/jitter on
- * some hardware/driver combos. Smooth it out to get kinder, gentler behavior.
- * @param ev MotionEvent to add to the ongoing history
- */
- private void addTouchHistory(MotionEvent ev) {
- final long currentTime = SystemClock.uptimeMillis();
- final int count = ev.getPointerCount();
- boolean accept = currentTime - mTouchHistoryLastAcceptedTime >= TOUCH_STABILIZE_TIME;
- float total = 0;
- int sampleCount = 0;
- for (int i = 0; i < count; i++) {
- final boolean hasLastAccepted = !Float.isNaN(mTouchHistoryLastAccepted);
- final int historySize = ev.getHistorySize();
- final int pointerSampleCount = historySize + 1;
- for (int h = 0; h < pointerSampleCount; h++) {
- float major;
- if (h < historySize) {
- major = ev.getHistoricalTouchMajor(i, h);
- } else {
- major = ev.getTouchMajor(i);
- }
- if (major < mTouchMinMajor) major = mTouchMinMajor;
- total += major;
-
- if (Float.isNaN(mTouchUpper) || major > mTouchUpper) {
- mTouchUpper = major;
- }
- if (Float.isNaN(mTouchLower) || major < mTouchLower) {
- mTouchLower = major;
- }
-
- if (hasLastAccepted) {
- final int directionSig = (int) Math.signum(major - mTouchHistoryLastAccepted);
- if (directionSig != mTouchHistoryDirection ||
- (directionSig == 0 && mTouchHistoryDirection == 0)) {
- mTouchHistoryDirection = directionSig;
- final long time = h < historySize ? ev.getHistoricalEventTime(h)
- : ev.getEventTime();
- mTouchHistoryLastAcceptedTime = time;
- accept = false;
- }
- }
- }
- sampleCount += pointerSampleCount;
- }
-
- final float avg = total / sampleCount;
-
- if (accept) {
- float newAccepted = (mTouchUpper + mTouchLower + avg) / 3;
- mTouchUpper = (mTouchUpper + newAccepted) / 2;
- mTouchLower = (mTouchLower + newAccepted) / 2;
- mTouchHistoryLastAccepted = newAccepted;
- mTouchHistoryDirection = 0;
- mTouchHistoryLastAcceptedTime = ev.getEventTime();
- }
- }
-
- /**
- * Clear all touch history tracking. Useful in ACTION_CANCEL or ACTION_UP.
- * @see #addTouchHistory(MotionEvent)
- */
- private void clearTouchHistory() {
- mTouchUpper = Float.NaN;
- mTouchLower = Float.NaN;
- mTouchHistoryLastAccepted = Float.NaN;
- mTouchHistoryDirection = 0;
- mTouchHistoryLastAcceptedTime = 0;
- }
-
- /**
* Accepts MotionEvents and dispatches events to a {@link OnScaleGestureListener}
* when appropriate.
*
@@ -344,7 +264,6 @@
}
if (streamComplete) {
- clearTouchHistory();
return true;
}
}
@@ -391,17 +310,14 @@
focusY = sumY / div;
}
- addTouchHistory(event);
-
// Determine average deviation from focal point
float devSumX = 0, devSumY = 0;
for (int i = 0; i < count; i++) {
if (skipIndex == i) continue;
// Convert the resulting diameter into a radius.
- final float touchSize = mTouchHistoryLastAccepted / 2;
- devSumX += Math.abs(event.getX(i) - focusX) + touchSize;
- devSumY += Math.abs(event.getY(i) - focusY) + touchSize;
+ devSumX += Math.abs(event.getX(i) - focusX);
+ devSumY += Math.abs(event.getY(i) - focusY);
}
final float devX = devSumX / div;
final float devY = devSumY / div;
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index c972476..df774b4 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -794,7 +794,8 @@
}
final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo;
- int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length);
+ int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length,
+ mRootNode.mNativeRenderNode);
if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
setEnabled(false);
attachInfo.mViewRootImpl.mSurface.release();
@@ -993,7 +994,8 @@
private static native void nSetLightCenter(long nativeProxy,
float lightX, float lightY, float lightZ);
private static native void nSetOpaque(long nativeProxy, boolean opaque);
- private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
+ private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size,
+ long rootRenderNode);
private static native void nDestroy(long nativeProxy, long rootRenderNode);
private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index dd79e62..b95d830 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2434,6 +2434,7 @@
* 11111111 PFLAG3_POINTER_ICON_MASK
* 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE
* 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED
+ * 1 PFLAG3_TEMPORARY_DETACH
* |-------|-------|-------|-------|
*/
@@ -2667,6 +2668,14 @@
*/
private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000;
+ /**
+ * Flag indicating that the view is temporarily detached from the parent view.
+ *
+ * @see #onStartTemporaryDetach()
+ * @see #onFinishTemporaryDetach()
+ */
+ static final int PFLAG3_TEMPORARY_DETACH = 0x2000000;
+
/* End of masks for mPrivateFlags3 */
/**
@@ -3890,6 +3899,7 @@
* cleanup.
*/
final RenderNode mRenderNode;
+ private Runnable mRenderNodeDetachedCallback;
/**
* Set to true when the view is sending hover accessibility events because it
@@ -9735,9 +9745,20 @@
}
/**
- * @hide
+ * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()}
+ * and {@link #onFinishTemporaryDetach()}.
*/
+ public final boolean isTemporarilyDetached() {
+ return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0;
+ }
+
+ /**
+ * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is
+ * a container View.
+ */
+ @CallSuper
public void dispatchStartTemporaryDetach() {
+ mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH;
onStartTemporaryDetach();
}
@@ -9753,10 +9774,13 @@
}
/**
- * @hide
+ * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is
+ * a container View.
*/
+ @CallSuper
public void dispatchFinishTemporaryDetach() {
onFinishTemporaryDetach();
+ mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH;
}
/**
@@ -15187,6 +15211,7 @@
protected void onDetachedFromWindowInternal() {
mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT;
+ mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH;
removeUnsetPressCallback();
removeLongPressCallback();
@@ -16009,6 +16034,27 @@
}
/**
+ * Called when the passed RenderNode is removed from the draw tree
+ * @hide
+ */
+ public void onRenderNodeDetached(RenderNode renderNode) {
+ if (renderNode == mRenderNode && mRenderNodeDetachedCallback != null) {
+ mRenderNodeDetachedCallback.run();
+ }
+ }
+
+ /**
+ * Set callback for functor detach. Exposed to WebView through WebViewDelegate.
+ * Should not be used otherwise.
+ * @hide
+ */
+ public final Runnable setRenderNodeDetachedCallback(@Nullable Runnable callback) {
+ Runnable oldCallback = mRenderNodeDetachedCallback;
+ mRenderNodeDetachedCallback = callback;
+ return oldCallback;
+ }
+
+ /**
* <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p>
*
* @return A non-scaled bitmap representing this view or null if cache is disabled.
@@ -16908,7 +16954,7 @@
}
} else if (cache != null) {
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
- if (layerType == LAYER_TYPE_NONE) {
+ if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) {
// no layer paint, use temporary paint to draw bitmap
Paint cachePaint = parent.mCachePaint;
if (cachePaint == null) {
@@ -16920,13 +16966,12 @@
canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
} else {
// use layer paint to draw the bitmap, merging the two alphas, but also restore
- int layerPaintAlpha = mLayerPaint != null ? mLayerPaint.getAlpha() : 255;
- if (mLayerPaint == null && alpha < 1) {
- mLayerPaint = new Paint();
+ int layerPaintAlpha = mLayerPaint.getAlpha();
+ if (alpha < 1) {
mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha));
}
canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint);
- if (mLayerPaint != null) {
+ if (alpha < 1) {
mLayerPaint.setAlpha(layerPaintAlpha);
}
}
@@ -18072,13 +18117,7 @@
* to clear the previous drawable. setVisible first while we still have the callback set.
*/
if (mBackground != null) {
- // It's possible for this method to be invoked from the View constructor before
- // subclass constructors have run. Drawables can and should trigger invalidations
- // and other activity with their callback on visibility changes, which shouldn't
- // happen before subclass constructors finish. However, we won't have set the
- // drawable as visible until the view becomes attached. This guard below keeps
- // multiple calls to this method from constructors from causing issues.
- if (mBackground.isVisible()) {
+ if (isAttachedToWindow()) {
mBackground.setVisible(false, false);
}
mBackground.setCallback(null);
@@ -18313,13 +18352,7 @@
}
if (mForegroundInfo.mDrawable != null) {
- // It's possible for this method to be invoked from the View constructor before
- // subclass constructors have run. Drawables can and should trigger invalidations
- // and other activity with their callback on visibility changes, which shouldn't
- // happen before subclass constructors finish. However, we won't have set the
- // drawable as visible until the view becomes attached. This guard below keeps
- // multiple calls to this method from constructors from causing issues.
- if (mForegroundInfo.mDrawable.isVisible()) {
+ if (isAttachedToWindow()) {
mForegroundInfo.mDrawable.setVisible(false, false);
}
mForegroundInfo.mDrawable.setCallback(null);
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index f18b7ac..c604234 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -1110,6 +1110,13 @@
@Override
public void onAnimationEnd(Animator animation) {
mView.setHasTransientState(false);
+ if (mAnimatorCleanupMap != null) {
+ Runnable r = mAnimatorCleanupMap.get(animation);
+ if (r != null) {
+ r.run();
+ }
+ mAnimatorCleanupMap.remove(animation);
+ }
if (mListener != null) {
mListener.onAnimationEnd(animation);
}
@@ -1120,13 +1127,6 @@
}
mAnimatorOnEndMap.remove(animation);
}
- if (mAnimatorCleanupMap != null) {
- Runnable r = mAnimatorCleanupMap.get(animation);
- if (r != null) {
- r.run();
- }
- mAnimatorCleanupMap.remove(animation);
- }
mAnimatorMap.remove(animation);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5d4ee874..5b2877f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -774,7 +774,7 @@
* has invoked. If false, the functor may be invoked
* asynchronously.
*/
- public void invokeFunctor(long functor, boolean waitForCompletion) {
+ public static void invokeFunctor(long functor, boolean waitForCompletion) {
ThreadedRenderer.invokeFunctor(functor, waitForCompletion);
}
@@ -3415,6 +3415,13 @@
updateConfiguration(config, false);
}
+ final boolean framesChanged = !mWinFrame.equals(args.arg1)
+ || !mPendingOverscanInsets.equals(args.arg5)
+ || !mPendingContentInsets.equals(args.arg2)
+ || !mPendingStableInsets.equals(args.arg6)
+ || !mPendingVisibleInsets.equals(args.arg3)
+ || !mPendingOutsets.equals(args.arg7);
+
mWinFrame.set((Rect) args.arg1);
mPendingOverscanInsets.set((Rect) args.arg5);
mPendingContentInsets.set((Rect) args.arg2);
@@ -3431,7 +3438,7 @@
mReportNextDraw = true;
}
- if (mView != null) {
+ if (mView != null && framesChanged) {
forceLayout(mView);
}
diff --git a/core/java/android/view/WindowInfo.java b/core/java/android/view/WindowInfo.java
index b721074..737e4607 100644
--- a/core/java/android/view/WindowInfo.java
+++ b/core/java/android/view/WindowInfo.java
@@ -44,6 +44,8 @@
public boolean focused;
public final Rect boundsInScreen = new Rect();
public List<IBinder> childTokens;
+ public CharSequence title;
+ public int accessibilityIdOfAnchor = View.NO_ID;
private WindowInfo() {
/* do nothing - hide constructor */
@@ -65,6 +67,8 @@
window.parentToken = other.parentToken;
window.focused = other.focused;
window.boundsInScreen.set(other.boundsInScreen);
+ window.title = other.title;
+ window.accessibilityIdOfAnchor = other.accessibilityIdOfAnchor;
if (other.childTokens != null && !other.childTokens.isEmpty()) {
if (window.childTokens == null) {
@@ -95,6 +99,8 @@
parcel.writeStrongBinder(parentToken);
parcel.writeInt(focused ? 1 : 0);
boundsInScreen.writeToParcel(parcel, flags);
+ parcel.writeCharSequence(title);
+ parcel.writeInt(accessibilityIdOfAnchor);
if (childTokens != null && !childTokens.isEmpty()) {
parcel.writeInt(1);
@@ -108,13 +114,15 @@
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("WindowInfo[");
- builder.append("type=").append(type);
+ builder.append("title=").append(title);
+ builder.append(", type=").append(type);
builder.append(", layer=").append(layer);
builder.append(", token=").append(token);
builder.append(", bounds=").append(boundsInScreen);
builder.append(", parent=").append(parentToken);
builder.append(", focused=").append(focused);
builder.append(", children=").append(childTokens);
+ builder.append(", accessibility anchor=").append(accessibilityIdOfAnchor);
builder.append(']');
return builder.toString();
}
@@ -126,6 +134,8 @@
parentToken = parcel.readStrongBinder();
focused = (parcel.readInt() == 1);
boundsInScreen.readFromParcel(parcel);
+ title = parcel.readCharSequence();
+ accessibilityIdOfAnchor = parcel.readInt();
final boolean hasChildren = (parcel.readInt() == 1);
if (hasChildren) {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 03dcf99..c372c30 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1693,6 +1693,14 @@
*/
public long userActivityTimeout = -1;
+ /**
+ * For windows with an anchor (e.g. PopupWindow), keeps track of the View that anchors the
+ * window.
+ *
+ * @hide
+ */
+ public int accessibilityIdOfAnchor = -1;
+
public LayoutParams() {
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
type = TYPE_APPLICATION;
@@ -1799,6 +1807,7 @@
out.writeInt(surfaceInsets.bottom);
out.writeInt(hasManualSurfaceInsets ? 1 : 0);
out.writeInt(needsMenuKey);
+ out.writeInt(accessibilityIdOfAnchor);
}
public static final Parcelable.Creator<LayoutParams> CREATOR
@@ -1849,6 +1858,7 @@
surfaceInsets.bottom = in.readInt();
hasManualSurfaceInsets = in.readInt() != 0;
needsMenuKey = in.readInt();
+ accessibilityIdOfAnchor = in.readInt();
}
@SuppressWarnings({"PointlessBitwiseExpression"})
@@ -1888,6 +1898,8 @@
/** {@hide} */
public static final int PREFERRED_DISPLAY_MODE_ID = 1 << 23;
/** {@hide} */
+ public static final int ACCESSIBILITY_ANCHOR_CHANGED = 1 << 24;
+ /** {@hide} */
public static final int EVERYTHING_CHANGED = 0xffffffff;
// internal buffer to backup/restore parameters under compatibility mode.
@@ -2048,6 +2060,11 @@
changes |= NEEDS_MENU_KEY_CHANGED;
}
+ if (accessibilityIdOfAnchor != o.accessibilityIdOfAnchor) {
+ accessibilityIdOfAnchor = o.accessibilityIdOfAnchor;
+ changes |= ACCESSIBILITY_ANCHOR_CHANGED;
+ }
+
return changes;
}
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 2cde03d..f8a13a3 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -240,10 +240,12 @@
* <li>{@link #getMovementGranularity()} - Sets the granularity at which a view's text
* was traversed.</li>
* <li>{@link #getText()} - The text of the source's sub-tree.</li>
- * <li>{@link #getFromIndex()} - The start of the next/previous text at the specified granularity
- * - inclusive.</li>
- * <li>{@link #getToIndex()} - The end of the next/previous text at the specified granularity
- * - exclusive.</li>
+ * <li>{@link #getFromIndex()} - The start the text that was skipped over in this movement.
+ * This is the starting point when moving forward through the text, but not when moving
+ * back.</li>
+ * <li>{@link #getToIndex()} - The end of the text that was skipped over in this movement.
+ * This is the ending point when moving forward through the text, but not when moving
+ * back.</li>
* <li>{@link #isPassword()} - Whether the source is password.</li>
* <li>{@link #isEnabled()} - Whether the source is enabled.</li>
* <li>{@link #getContentDescription()} - The content description of the source.</li>
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index ad78b68..d0d4507 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -89,6 +89,8 @@
private int mParentId = UNDEFINED;
private final Rect mBoundsInScreen = new Rect();
private LongArray mChildIds;
+ private CharSequence mTitle;
+ private int mAnchorId = UNDEFINED;
private int mConnectionId = UNDEFINED;
@@ -97,6 +99,26 @@
}
/**
+ * Gets the title of the window.
+ *
+ * @return The title.
+ */
+ public CharSequence getTitle() {
+ return mTitle;
+ }
+
+ /**
+ * Sets the title of the window.
+ *
+ * @param title The title.
+ *
+ * @hide
+ */
+ public void setTitle(CharSequence title) {
+ mTitle = title;
+ }
+
+ /**
* Gets the type of the window.
*
* @return The type.
@@ -159,9 +181,35 @@
}
/**
- * Gets the parent window if such.
+ * Sets the anchor node's ID.
*
- * @return The parent window.
+ * @param anchorId The anchor's accessibility id in its window.
+ *
+ * @hide
+ */
+ public void setAnchorId(int anchorId) {
+ mAnchorId = anchorId;
+ }
+
+ /**
+ * Gets the node that anchors this window to another.
+ *
+ * @return The anchor node, or {@code null} if none exists.
+ */
+ public AccessibilityNodeInfo getAnchor() {
+ if ((mConnectionId == UNDEFINED) || (mAnchorId == UNDEFINED) || (mParentId == UNDEFINED)) {
+ return null;
+ }
+
+ AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
+ return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
+ mParentId, mAnchorId, true, 0);
+ }
+
+ /**
+ * Gets the parent window.
+ *
+ * @return The parent window, or {@code null} if none exists.
*/
public AccessibilityWindowInfo getParent() {
if (mConnectionId == UNDEFINED || mParentId == UNDEFINED) {
@@ -370,6 +418,8 @@
infoClone.mId = info.mId;
infoClone.mParentId = info.mParentId;
infoClone.mBoundsInScreen.set(info.mBoundsInScreen);
+ infoClone.mTitle = info.mTitle;
+ infoClone.mAnchorId = info.mAnchorId;
if (info.mChildIds != null && info.mChildIds.size() > 0) {
if (infoClone.mChildIds == null) {
@@ -410,6 +460,8 @@
parcel.writeInt(mId);
parcel.writeInt(mParentId);
mBoundsInScreen.writeToParcel(parcel, flags);
+ parcel.writeCharSequence(mTitle);
+ parcel.writeInt(mAnchorId);
final LongArray childIds = mChildIds;
if (childIds == null) {
@@ -432,6 +484,8 @@
mId = parcel.readInt();
mParentId = parcel.readInt();
mBoundsInScreen.readFromParcel(parcel);
+ mTitle = parcel.readCharSequence();
+ mAnchorId = parcel.readInt();
final int childCount = parcel.readInt();
if (childCount > 0) {
@@ -471,6 +525,7 @@
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("AccessibilityWindowInfo[");
+ builder.append("title=").append(mTitle);
builder.append("id=").append(mId);
builder.append(", type=").append(typeToString(mType));
builder.append(", layer=").append(mLayer);
@@ -494,6 +549,7 @@
builder.append(']');
} else {
builder.append(", hasParent=").append(mParentId != UNDEFINED);
+ builder.append(", isAnchored=").append(mAnchorId != UNDEFINED);
builder.append(", hasChildren=").append(mChildIds != null
&& mChildIds.size() > 0);
}
@@ -515,6 +571,8 @@
mChildIds.clear();
}
mConnectionId = UNDEFINED;
+ mAnchorId = UNDEFINED;
+ mTitle = null;
}
/**
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 6879901..1ce80434 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1307,6 +1307,12 @@
void focusInLocked(View view) {
if (DEBUG) Log.v(TAG, "focusIn: " + dumpViewInfo(view));
+ if (view != null && view.isTemporarilyDetached()) {
+ // This is a request from a view that is temporarily detached from a window.
+ if (DEBUG) Log.v(TAG, "Temporarily detached view, ignoring");
+ return;
+ }
+
if (mCurRootView != view.getRootView()) {
// This is a request from a window that isn't in the window with
// IME focus, so ignore it.
@@ -1332,6 +1338,7 @@
// whenever we go into touch mode, so it ends up hiding
// at times when we don't really want it to. For now it
// seems better to just turn it all off.
+ // TODO: Check view.isTemporarilyDetached() when re-enable the following code.
if (false && view.hasWindowFocus()) {
mNextServedView = null;
scheduleCheckFocusLocked(view);
@@ -1348,7 +1355,7 @@
synchronized (mH) {
if (DEBUG) Log.v(TAG, "onViewDetachedFromWindow: view=" + dumpViewInfo(view)
+ " mServedView=" + dumpViewInfo(mServedView));
- if (mServedView == view && view.hasWindowFocus()) {
+ if (mServedView == view) {
mNextServedView = null;
scheduleCheckFocusLocked(view);
}
@@ -2315,6 +2322,7 @@
sb.append(",focus=" + view.hasFocus());
sb.append(",windowFocus=" + view.hasWindowFocus());
sb.append(",window=" + view.getWindowToken());
+ sb.append(",temporaryDetach=" + view.isTemporarilyDetached());
return sb.toString();
}
}
diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java
index 94dc03c..b6516c8 100644
--- a/core/java/android/webkit/WebViewDelegate.java
+++ b/core/java/android/webkit/WebViewDelegate.java
@@ -16,6 +16,8 @@
package android.webkit;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.ActivityThread;
import android.app.Application;
@@ -86,8 +88,7 @@
*/
public void invokeDrawGlFunctor(View containerView, long nativeDrawGLFunctor,
boolean waitForCompletion) {
- ViewRootImpl viewRootImpl = containerView.getViewRootImpl();
- viewRootImpl.invokeFunctor(nativeDrawGLFunctor, waitForCompletion);
+ ViewRootImpl.invokeFunctor(nativeDrawGLFunctor, waitForCompletion);
}
/**
@@ -110,6 +111,24 @@
}
/**
+ * Set the Runnable callback the DrawGlFunction functor is detached and free to be destroyed.
+ * This will replace the previous callback, if any.
+ *
+ * @param view The view to set the callback. Should be the view where onDraw inserted
+ * DrawGLFunctor.
+ * @param callback The new callback to set on the view.
+ * @throws IllegalArgumentException if view is null.
+ * @return The previous callback on this view.
+ */
+ public Runnable setDrawGlFunctionDetachedCallback(
+ @NonNull View view, @Nullable Runnable callback) {
+ if (view == null) {
+ throw new IllegalArgumentException("View cannot be null");
+ }
+ return view.setRenderNodeDetachedCallback(callback);
+ }
+
+ /**
* Detaches the draw GL functor.
*
* @param nativeDrawGLFunctor the pointer to the native functor that implements
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index d884f19..0ac5731 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -21,7 +21,6 @@
import android.app.AppGlobals;
import android.app.Application;
import android.content.Context;
-import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -561,20 +560,12 @@
return result;
}
- /**
- * Returns whether the entire package from an ACTION_PACKAGE_CHANGED intent was changed (rather
- * than just one of its components).
- * @hide
- */
- public static boolean entirePackageChanged(Intent intent) {
- String[] componentList =
- intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
- return Arrays.asList(componentList).contains(
- intent.getDataString().substring("package:".length()));
- }
+ private static String WEBVIEW_UPDATE_SERVICE_NAME = "webviewupdate";
- private static IWebViewUpdateService getUpdateService() {
- return IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
+ /** @hide */
+ public static IWebViewUpdateService getUpdateService() {
+ return IWebViewUpdateService.Stub.asInterface(
+ ServiceManager.getService(WEBVIEW_UPDATE_SERVICE_NAME));
}
private static native boolean nativeReserveAddressSpace(long addressSpaceToReserve);
diff --git a/core/java/android/webkit/WebViewProviderInfo.java b/core/java/android/webkit/WebViewProviderInfo.java
index 75ccf35..5d091c9 100644
--- a/core/java/android/webkit/WebViewProviderInfo.java
+++ b/core/java/android/webkit/WebViewProviderInfo.java
@@ -16,32 +16,20 @@
package android.webkit;
-import android.app.AppGlobals;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.Signature;
-import android.os.Build;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.AndroidRuntimeException;
-import android.util.Base64;
import java.util.Arrays;
-/** @hide */
-public class WebViewProviderInfo implements Parcelable {
+/**
+ * @hide
+ */
+@SystemApi
+public final class WebViewProviderInfo implements Parcelable {
- /**
- * @hide
- */
- public static class WebViewPackageNotFoundException extends AndroidRuntimeException {
- public WebViewPackageNotFoundException(String message) { super(message); }
- public WebViewPackageNotFoundException(Exception e) { super(e); }
- }
-
- public WebViewProviderInfo(String packageName, String description, boolean availableByDefault,
- boolean isFallback, String[] signatures) {
+ public WebViewProviderInfo(String packageName, String description,
+ boolean availableByDefault, boolean isFallback, String[] signatures) {
this.packageName = packageName;
this.description = description;
this.availableByDefault = availableByDefault;
@@ -49,92 +37,6 @@
this.signatures = signatures;
}
- private boolean hasValidSignature() {
- if (Build.IS_DEBUGGABLE)
- return true;
- Signature[] packageSignatures;
- try {
- // If no signature is declared, instead check whether the package is included in the
- // system.
- if (signatures == null || signatures.length == 0)
- return getPackageInfo().applicationInfo.isSystemApp();
-
- packageSignatures = getPackageInfo().signatures;
- } catch (WebViewPackageNotFoundException e) {
- return false;
- }
- if (packageSignatures.length != 1)
- return false;
-
- final byte[] packageSignature = packageSignatures[0].toByteArray();
- // Return whether the package signature matches any of the valid signatures
- for (String signature : signatures) {
- final byte[] validSignature = Base64.decode(signature, Base64.DEFAULT);
- if (Arrays.equals(packageSignature, validSignature))
- return true;
- }
- return false;
- }
-
- /**
- * Returns whether this provider is valid for use as a WebView provider.
- */
- public boolean isValidProvider() {
- ApplicationInfo applicationInfo;
- try {
- applicationInfo = getPackageInfo().applicationInfo;
- } catch (WebViewPackageNotFoundException e) {
- return false;
- }
- if (hasValidSignature() && WebViewFactory.getWebViewLibrary(applicationInfo) != null) {
- return true;
- }
- return false;
- }
-
- /**
- * Returns whether this package is enabled.
- * This state can be changed by the user from Settings->Apps
- */
- public boolean isEnabled() {
- try {
- // Explicitly fetch up-to-date package info here since the enabled-state of the package
- // might have changed since we last fetched its package info.
- updatePackageInfo();
- return getPackageInfo().applicationInfo.enabled;
- } catch (WebViewPackageNotFoundException e) {
- return false;
- }
- }
-
- /**
- * Returns whether the provider is always available as long as it is valid.
- * If this returns false, the provider will only be used if the user chose this provider.
- */
- public boolean isAvailableByDefault() {
- return availableByDefault;
- }
-
- public boolean isFallbackPackage() {
- return isFallback;
- }
-
- private void updatePackageInfo() {
- try {
- PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
- packageInfo = pm.getPackageInfo(packageName, PACKAGE_FLAGS);
- } catch (PackageManager.NameNotFoundException e) {
- throw new WebViewPackageNotFoundException(e);
- }
- }
-
- public PackageInfo getPackageInfo() {
- if (packageInfo == null) {
- updatePackageInfo();
- }
- return packageInfo;
- }
-
// aidl stuff
public static final Parcelable.Creator<WebViewProviderInfo> CREATOR =
new Parcelable.Creator<WebViewProviderInfo>() {
@@ -153,7 +55,6 @@
availableByDefault = (in.readInt() > 0);
isFallback = (in.readInt() > 0);
signatures = in.createStringArray();
- packageInfo = null;
}
@Override
@@ -171,16 +72,9 @@
}
// fields read from framework resource
- public String packageName;
- public String description;
- private boolean availableByDefault;
- private boolean isFallback;
-
- private String[] signatures;
-
- private PackageInfo packageInfo;
-
- // flags declaring we want extra info from the package manager
- private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
- | PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+ public final String packageName;
+ public final String description;
+ public final boolean availableByDefault;
+ public final boolean isFallback;
+ public final String[] signatures;
}
diff --git a/core/java/android/webkit/WebViewUpdateService.java b/core/java/android/webkit/WebViewUpdateService.java
new file mode 100644
index 0000000..4e83d88
--- /dev/null
+++ b/core/java/android/webkit/WebViewUpdateService.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 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.webkit;
+
+import android.annotation.SystemApi;
+import android.os.RemoteException;
+
+/**
+ * @hide
+ */
+@SystemApi
+public final class WebViewUpdateService {
+
+ private WebViewUpdateService () {}
+
+ /**
+ * Fetch all packages that could potentially implement WebView.
+ */
+ public static WebViewProviderInfo[] getAllWebViewPackages() {
+ try {
+ return getUpdateService().getAllWebViewPackages();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Fetch all packages that could potentially implement WebView and are currently valid.
+ */
+ public static WebViewProviderInfo[] getValidWebViewPackages() {
+ try {
+ return getUpdateService().getValidWebViewPackages();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Used by DevelopmentSetting to get the name of the WebView provider currently in use.
+ */
+ public static String getCurrentWebViewPackageName() {
+ try {
+ return getUpdateService().getCurrentWebViewPackageName();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static IWebViewUpdateService getUpdateService() {
+ return WebViewFactory.getUpdateService();
+ }
+}
diff --git a/core/java/android/widget/AccessibilityIterators.java b/core/java/android/widget/AccessibilityIterators.java
index a3d58a4..442ffa1 100644
--- a/core/java/android/widget/AccessibilityIterators.java
+++ b/core/java/android/widget/AccessibilityIterators.java
@@ -134,8 +134,8 @@
@Override
public int[] following(int offset) {
- final int textLegth = mText.length();
- if (textLegth <= 0) {
+ final int textLength = mText.length();
+ if (textLength <= 0) {
return null;
}
if (offset >= mText.length()) {
@@ -163,8 +163,8 @@
@Override
public int[] preceding(int offset) {
- final int textLegth = mText.length();
- if (textLegth <= 0) {
+ final int textLength = mText.length();
+ if (textLength <= 0) {
return null;
}
if (offset <= 0) {
@@ -181,8 +181,13 @@
final int pageHeight = mTempRect.height() - mView.getTotalPaddingTop()
- mView.getTotalPaddingBottom();
final int previousPageEndY = currentLineTop - pageHeight;
- final int currentPageStartLine = (previousPageEndY > 0) ?
- mLayout.getLineForVertical(previousPageEndY) + 1 : 0;
+ int currentPageStartLine = (previousPageEndY > 0) ?
+ mLayout.getLineForVertical(previousPageEndY) : 0;
+ // If we're at the end of text, we're at the end of the current line rather than the
+ // start of the next line, so we should move up one fewer lines than we would otherwise.
+ if (end == mText.length() && (currentPageStartLine < currentLine)) {
+ currentPageStartLine += 1;
+ }
final int start = getLineEdgeIndex(currentPageStartLine, DIRECTION_START);
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index 027f6d6..9d228cf 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -20,6 +20,7 @@
import android.annotation.IdRes;
import android.annotation.LayoutRes;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
import android.util.Log;
@@ -61,17 +62,13 @@
private final LayoutInflater mInflater;
- /**
- * Contains the list of objects that represent the data of this ArrayAdapter.
- * The content of this list is referred to as "the array" in the documentation.
- */
- private List<T> mObjects;
+ private final Context mContext;
/**
* The resource indicating what views to inflate to display the content of this
* array adapter.
*/
- private int mResource;
+ private final int mResource;
/**
* The resource indicating what views to inflate to display the content of this
@@ -80,7 +77,13 @@
private int mDropDownResource;
/**
- * If the inflated resource is not a TextView, {@link #mFieldId} is used to find
+ * Contains the list of objects that represent the data of this ArrayAdapter.
+ * The content of this list is referred to as "the array" in the documentation.
+ */
+ private List<T> mObjects;
+
+ /**
+ * If the inflated resource is not a TextView, {@code mFieldId} is used to find
* a TextView inside the inflated views hierarchy. This field must contain the
* identifier that matches the one defined in the resource file.
*/
@@ -92,8 +95,6 @@
*/
private boolean mNotifyOnChange = true;
- private Context mContext;
-
// A copy of the original mObjects array, initialized from and then used instead as soon as
// the mFilter ArrayFilter is used. mObjects will then only contain the filtered values.
private ArrayList<T> mOriginalValues;
@@ -109,8 +110,8 @@
* @param resource The resource ID for a layout file containing a TextView to use when
* instantiating views.
*/
- public ArrayAdapter(Context context, @LayoutRes int resource) {
- this(context, resource, 0, new ArrayList<T>());
+ public ArrayAdapter(@NonNull Context context, @LayoutRes int resource) {
+ this(context, resource, 0, new ArrayList<>());
}
/**
@@ -121,8 +122,9 @@
* instantiating views.
* @param textViewResourceId The id of the TextView within the layout resource to be populated
*/
- public ArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId) {
- this(context, resource, textViewResourceId, new ArrayList<T>());
+ public ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
+ @IdRes int textViewResourceId) {
+ this(context, resource, textViewResourceId, new ArrayList<>());
}
/**
@@ -133,7 +135,7 @@
* instantiating views.
* @param objects The objects to represent in the ListView.
*/
- public ArrayAdapter(Context context, @LayoutRes int resource, @NonNull T[] objects) {
+ public ArrayAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull T[] objects) {
this(context, resource, 0, Arrays.asList(objects));
}
@@ -146,8 +148,8 @@
* @param textViewResourceId The id of the TextView within the layout resource to be populated
* @param objects The objects to represent in the ListView.
*/
- public ArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId,
- @NonNull T[] objects) {
+ public ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
+ @IdRes int textViewResourceId, @NonNull T[] objects) {
this(context, resource, textViewResourceId, Arrays.asList(objects));
}
@@ -159,7 +161,8 @@
* instantiating views.
* @param objects The objects to represent in the ListView.
*/
- public ArrayAdapter(Context context, @LayoutRes int resource, @NonNull List<T> objects) {
+ public ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
+ @NonNull List<T> objects) {
this(context, resource, 0, objects);
}
@@ -172,8 +175,8 @@
* @param textViewResourceId The id of the TextView within the layout resource to be populated
* @param objects The objects to represent in the ListView.
*/
- public ArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId,
- @NonNull List<T> objects) {
+ public ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
+ @IdRes int textViewResourceId, @NonNull List<T> objects) {
mContext = context;
mInflater = LayoutInflater.from(context);
mResource = mDropDownResource = resource;
@@ -186,7 +189,7 @@
*
* @param object The object to add at the end of the array.
*/
- public void add(T object) {
+ public void add(@Nullable T object) {
synchronized (mLock) {
if (mOriginalValues != null) {
mOriginalValues.add(object);
@@ -201,8 +204,17 @@
* Adds the specified Collection at the end of the array.
*
* @param collection The Collection to add at the end of the array.
+ * @throws UnsupportedOperationException if the <tt>addAll</tt> operation
+ * is not supported by this list
+ * @throws ClassCastException if the class of an element of the specified
+ * collection prevents it from being added to this list
+ * @throws NullPointerException if the specified collection contains one
+ * or more null elements and this list does not permit null
+ * elements, or if the specified collection is null
+ * @throws IllegalArgumentException if some property of an element of the
+ * specified collection prevents it from being added to this list
*/
- public void addAll(Collection<? extends T> collection) {
+ public void addAll(@NonNull Collection<? extends T> collection) {
synchronized (mLock) {
if (mOriginalValues != null) {
mOriginalValues.addAll(collection);
@@ -235,7 +247,7 @@
* @param object The object to insert into the array.
* @param index The index at which the object must be inserted.
*/
- public void insert(T object, int index) {
+ public void insert(@Nullable T object, int index) {
synchronized (mLock) {
if (mOriginalValues != null) {
mOriginalValues.add(index, object);
@@ -251,7 +263,7 @@
*
* @param object The object to remove.
*/
- public void remove(T object) {
+ public void remove(@Nullable T object) {
synchronized (mLock) {
if (mOriginalValues != null) {
mOriginalValues.remove(object);
@@ -282,7 +294,7 @@
* @param comparator The comparator used to sort the objects contained
* in this adapter.
*/
- public void sort(Comparator<? super T> comparator) {
+ public void sort(@NonNull Comparator<? super T> comparator) {
synchronized (mLock) {
if (mOriginalValues != null) {
Collections.sort(mOriginalValues, comparator);
@@ -293,9 +305,6 @@
if (mNotifyOnChange) notifyDataSetChanged();
}
- /**
- * {@inheritDoc}
- */
@Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
@@ -326,21 +335,17 @@
*
* @return The Context associated with this adapter.
*/
- public Context getContext() {
+ public @NonNull Context getContext() {
return mContext;
}
- /**
- * {@inheritDoc}
- */
+ @Override
public int getCount() {
return mObjects.size();
}
- /**
- * {@inheritDoc}
- */
- public T getItem(int position) {
+ @Override
+ public @Nullable T getItem(int position) {
return mObjects.get(position);
}
@@ -351,28 +356,25 @@
*
* @return The position of the specified item.
*/
- public int getPosition(T item) {
+ public int getPosition(@Nullable T item) {
return mObjects.indexOf(item);
}
- /**
- * {@inheritDoc}
- */
+ @Override
public long getItemId(int position) {
return position;
}
- /**
- * {@inheritDoc}
- */
- public View getView(int position, View convertView, ViewGroup parent) {
+ @Override
+ public @NonNull View getView(int position, @Nullable View convertView,
+ @NonNull ViewGroup parent) {
return createViewFromResource(mInflater, position, convertView, parent, mResource);
}
- private View createViewFromResource(LayoutInflater inflater, int position, View convertView,
- ViewGroup parent, int resource) {
- View view;
- TextView text;
+ private @NonNull View createViewFromResource(@NonNull LayoutInflater inflater, int position,
+ @Nullable View convertView, @NonNull ViewGroup parent, int resource) {
+ final View view;
+ final TextView text;
if (convertView == null) {
view = inflater.inflate(resource, parent, false);
@@ -387,6 +389,12 @@
} else {
// Otherwise, find the TextView field within the layout
text = (TextView) view.findViewById(mFieldId);
+
+ if (text == null) {
+ throw new RuntimeException("Failed to find view with ID "
+ + mContext.getResources().getResourceName(mFieldId)
+ + " in item layout");
+ }
}
} catch (ClassCastException e) {
Log.e("ArrayAdapter", "You must supply a resource ID for a TextView");
@@ -394,9 +402,9 @@
"ArrayAdapter requires the resource ID to be a TextView", e);
}
- T item = getItem(position);
+ final T item = getItem(position);
if (item instanceof CharSequence) {
- text.setText((CharSequence)item);
+ text.setText((CharSequence) item);
} else {
text.setText(item.toString());
}
@@ -426,7 +434,7 @@
* @see #getDropDownView(int, View, ViewGroup)
*/
@Override
- public void setDropDownViewTheme(Resources.Theme theme) {
+ public void setDropDownViewTheme(@Nullable Resources.Theme theme) {
if (theme == null) {
mDropDownInflater = null;
} else if (theme == mInflater.getContext().getTheme()) {
@@ -438,12 +446,13 @@
}
@Override
- public Resources.Theme getDropDownViewTheme() {
+ public @Nullable Resources.Theme getDropDownViewTheme() {
return mDropDownInflater == null ? null : mDropDownInflater.getContext().getTheme();
}
@Override
- public View getDropDownView(int position, View convertView, ViewGroup parent) {
+ public View getDropDownView(int position, @Nullable View convertView,
+ @NonNull ViewGroup parent) {
final LayoutInflater inflater = mDropDownInflater == null ? mInflater : mDropDownInflater;
return createViewFromResource(inflater, position, convertView, parent, mDropDownResource);
}
@@ -458,16 +467,14 @@
*
* @return An ArrayAdapter<CharSequence>.
*/
- public static ArrayAdapter<CharSequence> createFromResource(Context context,
+ public static @NonNull ArrayAdapter<CharSequence> createFromResource(@NonNull Context context,
@ArrayRes int textArrayResId, @LayoutRes int textViewResId) {
- CharSequence[] strings = context.getResources().getTextArray(textArrayResId);
- return new ArrayAdapter<CharSequence>(context, textViewResId, strings);
+ final CharSequence[] strings = context.getResources().getTextArray(textArrayResId);
+ return new ArrayAdapter<>(context, textViewResId, strings);
}
- /**
- * {@inheritDoc}
- */
- public Filter getFilter() {
+ @Override
+ public @NonNull Filter getFilter() {
if (mFilter == null) {
mFilter = new ArrayFilter();
}
@@ -482,31 +489,31 @@
private class ArrayFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence prefix) {
- FilterResults results = new FilterResults();
+ final FilterResults results = new FilterResults();
if (mOriginalValues == null) {
synchronized (mLock) {
- mOriginalValues = new ArrayList<T>(mObjects);
+ mOriginalValues = new ArrayList<>(mObjects);
}
}
if (prefix == null || prefix.length() == 0) {
- ArrayList<T> list;
+ final ArrayList<T> list;
synchronized (mLock) {
- list = new ArrayList<T>(mOriginalValues);
+ list = new ArrayList<>(mOriginalValues);
}
results.values = list;
results.count = list.size();
} else {
- String prefixString = prefix.toString().toLowerCase();
+ final String prefixString = prefix.toString().toLowerCase();
- ArrayList<T> values;
+ final ArrayList<T> values;
synchronized (mLock) {
- values = new ArrayList<T>(mOriginalValues);
+ values = new ArrayList<>(mOriginalValues);
}
final int count = values.size();
- final ArrayList<T> newValues = new ArrayList<T>();
+ final ArrayList<T> newValues = new ArrayList<>();
for (int i = 0; i < count; i++) {
final T value = values.get(i);
@@ -517,11 +524,8 @@
newValues.add(value);
} else {
final String[] words = valueText.split(" ");
- final int wordCount = words.length;
-
- // Start at index 0, in case valueText starts with space(s)
- for (int k = 0; k < wordCount; k++) {
- if (words[k].startsWith(prefixString)) {
+ for (String word : words) {
+ if (word.startsWith(prefixString)) {
newValues.add(value);
break;
}
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 7d57cb8..6a4e36a 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -1116,7 +1116,7 @@
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
- if (mTemporaryDetach) {
+ if (isTemporarilyDetached()) {
// If we are temporarily in the detach state, then do nothing.
return;
}
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 6e3dbd8..e3357a7 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -75,8 +75,6 @@
*/
@Widget
public class DatePicker extends FrameLayout {
- private static final String LOG_TAG = DatePicker.class.getSimpleName();
-
private static final int MODE_SPINNER = 1;
private static final int MODE_CALENDAR = 2;
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index 5adac01..332e89c 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -378,9 +378,9 @@
mCurrentDate.set(Calendar.MONTH, monthOfYear);
mCurrentDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
- mDateChangedListener = callBack;
-
onDateChanged(false, false);
+
+ mDateChangedListener = callBack;
}
@Override
diff --git a/core/java/android/widget/DatePickerSpinnerDelegate.java b/core/java/android/widget/DatePickerSpinnerDelegate.java
index 255de79..d8a3c56 100644
--- a/core/java/android/widget/DatePickerSpinnerDelegate.java
+++ b/core/java/android/widget/DatePickerSpinnerDelegate.java
@@ -244,6 +244,7 @@
setDate(year, monthOfYear, dayOfMonth);
updateSpinners();
updateCalendarView();
+
mOnDateChangedListener = onDateChangedListener;
}
diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java
index 434e3eb..ad35550 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -155,6 +155,9 @@
public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
switch (action) {
case AccessibilityNodeInfo.ACTION_SET_TEXT: {
+ if (!isEnabled()) {
+ return false;
+ }
CharSequence text = (arguments != null) ? arguments.getCharSequence(
AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE) : null;
setText(text);
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 59d857c..7055f78 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -218,7 +218,6 @@
boolean mShowSoftInputOnFocus = true;
private boolean mPreserveSelection;
private boolean mRestartActionModeOnNextRefresh;
- boolean mTemporaryDetach;
boolean mIsBeingLongClicked;
@@ -367,7 +366,6 @@
showError();
mShowErrorAfterAttach = false;
}
- mTemporaryDetach = false;
final ViewTreeObserver observer = mTextView.getViewTreeObserver();
// No need to create the controller.
@@ -429,7 +427,6 @@
hideCursorAndSpanControllers();
stopTextActionModeWithPreservingSelection();
- mTemporaryDetach = false;
}
private void discardTextDisplayLists() {
@@ -1212,7 +1209,7 @@
stopTextActionModeWithPreservingSelection();
} else {
hideCursorAndSpanControllers();
- if (mTemporaryDetach) {
+ if (mTextView.isTemporarilyDetached()) {
stopTextActionModeWithPreservingSelection();
} else {
stopTextActionMode();
@@ -1866,9 +1863,9 @@
if (hasSelection) {
hideInsertionPointCursorController();
if (mTextActionMode == null) {
- if (mRestartActionModeOnNextRefresh || mTextView.isInExtractedMode()) {
+ if (mRestartActionModeOnNextRefresh) {
// To avoid distraction, newly start action mode only when selection action
- // mode is being restarted or in full screen extracted mode.
+ // mode is being restarted.
startSelectionActionMode();
}
} else if (selectionController == null || !selectionController.isActive()) {
@@ -3640,6 +3637,9 @@
}
if (menu.hasVisibleItems() || mode.getCustomView() != null) {
+ if (mHasSelection && !mTextView.hasTransientState()) {
+ mTextView.setHasTransientState(true);
+ }
return true;
} else {
return false;
@@ -4875,11 +4875,12 @@
@Override
protected int getOffsetAtCoordinate(@NonNull Layout layout, int line, float x) {
- final int primaryOffset = layout.getOffsetForHorizontal(line, x, true);
+ final float localX = mTextView.convertToLocalHorizontalCoordinate(x);
+ final int primaryOffset = layout.getOffsetForHorizontal(line, localX, true);
if (!layout.isLevelBoundary(primaryOffset)) {
return primaryOffset;
}
- final int secondaryOffset = layout.getOffsetForHorizontal(line, x, false);
+ final int secondaryOffset = layout.getOffsetForHorizontal(line, localX, false);
final int currentOffset = getCurrentCursorOffset();
final int primaryDiff = Math.abs(primaryOffset - currentOffset);
final int secondaryDiff = Math.abs(secondaryOffset - currentOffset);
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index fe8916b..9ac4917 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -16,17 +16,15 @@
package android.widget;
-import java.util.ArrayList;
+import com.android.internal.R;
+import android.annotation.AttrRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.StyleRes;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.PorterDuff;
import android.graphics.Rect;
-import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
@@ -36,8 +34,7 @@
import android.view.ViewHierarchyEncoder;
import android.widget.RemoteViews.RemoteView;
-import com.android.internal.R;
-
+import java.util.ArrayList;
/**
* FrameLayout is designed to block out an area on the screen to display
@@ -75,31 +72,29 @@
@ViewDebug.ExportedProperty(category = "padding")
private int mForegroundPaddingBottom = 0;
- private final Rect mSelfBounds = new Rect();
- private final Rect mOverlayBounds = new Rect();
-
- private final ArrayList<View> mMatchParentChildren = new ArrayList<View>(1);
-
- public FrameLayout(Context context) {
+ private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1);
+
+ public FrameLayout(@NonNull Context context) {
super(context);
}
-
- public FrameLayout(Context context, @Nullable AttributeSet attrs) {
+
+ public FrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
- public FrameLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ public FrameLayout(@NonNull Context context, @Nullable AttributeSet attrs,
+ @AttrRes int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
- public FrameLayout(
- Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ public FrameLayout(@NonNull Context context, @Nullable AttributeSet attrs,
+ @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
final TypedArray a = context.obtainStyledAttributes(
- attrs, com.android.internal.R.styleable.FrameLayout, defStyleAttr, defStyleRes);
-
- if (a.getBoolean(com.android.internal.R.styleable.FrameLayout_measureAllChildren, false)) {
+ attrs, R.styleable.FrameLayout, defStyleAttr, defStyleRes);
+
+ if (a.getBoolean(R.styleable.FrameLayout_measureAllChildren, false)) {
setMeasureAllChildren(true);
}
@@ -171,10 +166,6 @@
mPaddingBottom + mForegroundPaddingBottom;
}
-
- /**
- * {@inheritDoc}
- */
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int count = getChildCount();
@@ -264,17 +255,13 @@
}
}
}
-
- /**
- * {@inheritDoc}
- */
+
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
layoutChildren(left, top, right, bottom, false /* no force left gravity */);
}
- void layoutChildren(int left, int top, int right, int bottom,
- boolean forceLeftGravity) {
+ void layoutChildren(int left, int top, int right, int bottom, boolean forceLeftGravity) {
final int count = getChildCount();
final int parentLeft = getPaddingLeftWithForeground();
@@ -378,12 +365,9 @@
return mMeasureAllChildren;
}
- /**
- * {@inheritDoc}
- */
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
- return new FrameLayout.LayoutParams(getContext(), attrs);
+ return new FrameLayout.LayoutParams(getContext(), attrs);
}
@Override
@@ -391,9 +375,6 @@
return false;
}
- /**
- * {@inheritDoc}
- */
@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof LayoutParams;
@@ -431,34 +412,30 @@
* Per-child layout information for layouts that support margins.
* See {@link android.R.styleable#FrameLayout_Layout FrameLayout Layout Attributes}
* for a list of all child view attributes that this class supports.
- *
+ *
* @attr ref android.R.styleable#FrameLayout_Layout_layout_gravity
*/
public static class LayoutParams extends MarginLayoutParams {
/**
* The gravity to apply with the View to which these layout parameters
* are associated.
+ * <p>
+ * The default value is {@code Gravity.TOP | Gravity.START}
*
* @see android.view.Gravity
- *
* @attr ref android.R.styleable#FrameLayout_Layout_layout_gravity
*/
- public int gravity = -1;
+ public int gravity = DEFAULT_CHILD_GRAVITY;
- /**
- * {@inheritDoc}
- */
- public LayoutParams(Context c, AttributeSet attrs) {
+ public LayoutParams(@NonNull Context c, @Nullable AttributeSet attrs) {
super(c, attrs);
- TypedArray a = c.obtainStyledAttributes(attrs, com.android.internal.R.styleable.FrameLayout_Layout);
- gravity = a.getInt(com.android.internal.R.styleable.FrameLayout_Layout_layout_gravity, -1);
+ final TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.FrameLayout_Layout);
+ gravity = a.getInt(R.styleable.FrameLayout_Layout_layout_gravity,
+ DEFAULT_CHILD_GRAVITY);
a.recycle();
}
- /**
- * {@inheritDoc}
- */
public LayoutParams(int width, int height) {
super(width, height);
}
@@ -468,9 +445,9 @@
* and weight.
*
* @param width the width, either {@link #MATCH_PARENT},
- * {@link #WRAP_CONTENT} or a fixed size in pixels
+ * {@link #WRAP_CONTENT} or a fixed size in pixels
* @param height the height, either {@link #MATCH_PARENT},
- * {@link #WRAP_CONTENT} or a fixed size in pixels
+ * {@link #WRAP_CONTENT} or a fixed size in pixels
* @param gravity the gravity
*
* @see android.view.Gravity
@@ -480,17 +457,11 @@
this.gravity = gravity;
}
- /**
- * {@inheritDoc}
- */
- public LayoutParams(ViewGroup.LayoutParams source) {
+ public LayoutParams(@NonNull ViewGroup.LayoutParams source) {
super(source);
}
- /**
- * {@inheritDoc}
- */
- public LayoutParams(ViewGroup.MarginLayoutParams source) {
+ public LayoutParams(@NonNull ViewGroup.MarginLayoutParams source) {
super(source);
}
@@ -500,7 +471,7 @@
*
* @param source The layout params to copy from.
*/
- public LayoutParams(LayoutParams source) {
+ public LayoutParams(@NonNull LayoutParams source) {
super(source);
this.gravity = source.gravity;
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 0206577..222a040 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -911,17 +911,11 @@
}
if (mDrawable != null) {
- // It's possible for this method to be invoked from the constructor before
- // subclass constructors have run. Drawables can and should trigger invalidations
- // and other activity with their callback on visibility changes, which shouldn't
- // happen before subclass constructors finish. However, we won't have set the
- // drawable as visible until the view becomes attached. This guard below keeps
- // multiple calls to this method from constructors from causing issues.
- if (mDrawable.isVisible()) {
- mDrawable.setVisible(false, false);
- }
mDrawable.setCallback(null);
unscheduleDrawable(mDrawable);
+ if (isAttachedToWindow()) {
+ mDrawable.setVisible(false, false);
+ }
}
mDrawable = d;
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 7658cc8..bfc87f2 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1673,7 +1673,7 @@
focusLayoutRestoreView = findFocus();
if (focusLayoutRestoreView != null) {
// Tell it we are going to mess with it.
- focusLayoutRestoreView.onStartTemporaryDetach();
+ focusLayoutRestoreView.dispatchStartTemporaryDetach();
}
}
requestFocus();
@@ -1850,7 +1850,7 @@
// our view hierarchy.
if (focusLayoutRestoreView != null
&& focusLayoutRestoreView.getWindowToken() != null) {
- focusLayoutRestoreView.onFinishTemporaryDetach();
+ focusLayoutRestoreView.dispatchFinishTemporaryDetach();
}
mLayoutMode = LAYOUT_NORMAL;
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 92631da..0d8d8ed 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1214,6 +1214,7 @@
final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff,
p.width, p.height, gravity);
updateAboveAnchor(aboveAnchor);
+ p.accessibilityIdOfAnchor = (anchor != null) ? anchor.getAccessibilityViewId() : -1;
invokePopup(p);
}
@@ -1494,7 +1495,7 @@
*
* @param anchor the view on which the popup window must be anchored
* @param outParams the layout parameters used to display the drop down
- * @param xOffset absolute horizontal offset from the top of the anchor
+ * @param xOffset absolute horizontal offset from the left of the anchor
* @param yOffset absolute vertical offset from the top of the anchor
* @param gravity horizontal gravity specifying popup alignment
* @return true if the popup is translated upwards to fit on screen
@@ -1523,6 +1524,8 @@
// Let the window manager know to align the top to y.
outParams.gravity = Gravity.LEFT | Gravity.TOP;
+ outParams.width = width;
+ outParams.height = height;
final int[] screenLocation = mTmpScreenLocation;
anchor.getLocationOnScreen(screenLocation);
@@ -1530,100 +1533,154 @@
final Rect displayFrame = new Rect();
anchor.getWindowVisibleDisplayFrame(displayFrame);
- boolean onTop = false;
+ // First, attempt to fit the popup vertically without resizing.
+ final boolean fitsVertical = tryFitVertical(outParams, yOffset, height,
+ anchorHeight, drawingLocation[1], screenLocation[1], displayFrame.top,
+ displayFrame.bottom, false);
- final View root = anchor.getRootView();
- final int screenY = screenLocation[1] + anchorHeight + yOffset;
- final boolean tooFarDown = screenY + height > displayFrame.bottom;
- final boolean tooFarRight = outParams.x + width > root.getWidth();
- if (tooFarDown || tooFarRight) {
- // If the popup extends beyond the visible area, try to scroll the
- // parent so that it is fully visible.
- if (mAllowScrollingAnchorParent) {
- final int scrollX = anchor.getScrollX();
- final int scrollY = anchor.getScrollY();
- final Rect r = new Rect(scrollX, scrollY, scrollX + width + xOffset,
- scrollY + height + anchorHeight + yOffset);
- anchor.requestRectangleOnScreen(r, true);
- }
+ // Next, attempt to fit the popup horizontally without resizing.
+ final boolean fitsHorizontal = tryFitHorizontal(outParams, xOffset, width,
+ anchorWidth, drawingLocation[0], screenLocation[0], displayFrame.left,
+ displayFrame.right, false);
- // Update for the new anchor position.
- anchor.getLocationInWindow(drawingLocation);
- outParams.x = drawingLocation[0] + xOffset;
- outParams.y = drawingLocation[1] + anchorHeight + yOffset;
+ // If the popup still doesn't fit, attempt to scroll the parent.
+ if (!fitsVertical || !fitsHorizontal) {
+ final int scrollX = anchor.getScrollX();
+ final int scrollY = anchor.getScrollY();
+ final Rect r = new Rect(scrollX, scrollY, scrollX + width + xOffset,
+ scrollY + height + anchorHeight + yOffset);
+ if (mAllowScrollingAnchorParent && anchor.requestRectangleOnScreen(r, true)) {
+ // Reset for the new anchor position.
+ anchor.getLocationInWindow(drawingLocation);
+ outParams.x = drawingLocation[0] + xOffset;
+ outParams.y = drawingLocation[1] + anchorHeight + yOffset;
- // Preserve the gravity adjustment.
- if (hgrav == Gravity.RIGHT) {
- outParams.x -= width - anchorWidth;
- }
-
- final int newScreenY = screenLocation[1] + anchorHeight + yOffset;
- final boolean stillTooFarDown = newScreenY + height > displayFrame.bottom;
- if (stillTooFarDown) {
- // If the popup is still too far down, re-evaluate the space
- // available and decide whether the pop-up will go above or
- // below the anchor.
- anchor.getLocationOnScreen(screenLocation);
-
- final int below = displayFrame.bottom - screenLocation[1] - anchorHeight - yOffset;
- final int above = screenLocation[1] - displayFrame.top + yOffset;
- onTop = above > below;
-
- if (onTop) {
- // Move everything up.
- if (mOverlapAnchor) {
- yOffset += anchorHeight;
- }
- outParams.y = drawingLocation[1] - height + yOffset;
+ // Preserve the gravity adjustment.
+ if (hgrav == Gravity.RIGHT) {
+ outParams.x -= width - anchorWidth;
}
}
+
+ // Try to fit the popup again and allowing resizing.
+ tryFitVertical(outParams, yOffset, height, anchorHeight, drawingLocation[1],
+ screenLocation[1], displayFrame.top, displayFrame.bottom, mClipToScreen);
+ tryFitHorizontal(outParams, xOffset, width, anchorWidth, drawingLocation[0],
+ screenLocation[0], displayFrame.left, displayFrame.right, mClipToScreen);
}
- if (mClipToScreen) {
- // Use screen coordinates for comparison against display frame.
- final int winOffsetX = screenLocation[0] - drawingLocation[0];
- final int winOffsetY = screenLocation[1] - drawingLocation[1];
- outParams.x += winOffsetX;
- outParams.y += winOffsetY;
+ // Return whether the popup's top edge is above the anchor's top edge.
+ return outParams.y < drawingLocation[1];
+ }
- final int right = outParams.x + width;
- if (right > displayFrame.right) {
- // The popup is too far right, move it back in.
- outParams.x -= right - displayFrame.right;
- }
-
- if (outParams.x < displayFrame.left) {
- // The popup is too far left, move it back in and clip if it's
- // still too large.
- outParams.x = displayFrame.left;
-
- final int displayFrameWidth = displayFrame.width();
- width = Math.min(width, displayFrameWidth);
- }
-
- final int bottom = outParams.y + height;
- if (bottom > displayFrame.bottom) {
- // The popup is too far down, move it back in.
- outParams.y -= bottom - displayFrame.bottom;
- }
-
- if (outParams.y < displayFrame.top) {
- // The popup is too far up, move it back in and clip if
- // it's still too large.
- outParams.y = displayFrame.top;
-
- final int displayFrameHeight = displayFrame.height();
- height = Math.min(height, displayFrameHeight);
- }
-
- outParams.x -= winOffsetX;
- outParams.y -= winOffsetY;
+ private boolean tryFitVertical(@NonNull LayoutParams outParams, int yOffset, int height,
+ int anchorHeight, int drawingLocationY, int screenLocationY, int displayFrameTop,
+ int displayFrameBottom, boolean allowResize) {
+ final int anchorTopInScreen = screenLocationY + anchorHeight + yOffset;
+ final int spaceBelow = displayFrameBottom - anchorTopInScreen;
+ if (height <= spaceBelow) {
+ return true;
}
- outParams.width = width;
+ final int spaceAbove = displayFrameTop + anchorTopInScreen - anchorHeight;
+ if (height <= spaceAbove) {
+ // Move everything up.
+ if (mOverlapAnchor) {
+ yOffset += anchorHeight;
+ }
+ outParams.y = drawingLocationY - height + yOffset;
+
+ return true;
+ }
+
+ if (positionInDisplayVertical(outParams, height, drawingLocationY, screenLocationY,
+ displayFrameTop, displayFrameBottom, allowResize)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private boolean positionInDisplayVertical(@NonNull LayoutParams outParams, int height,
+ int drawingLocationY, int screenLocationY, int displayFrameTop, int displayFrameBottom,
+ boolean canResize) {
+ boolean fitsInDisplay = true;
+
+ final int winOffsetY = screenLocationY - drawingLocationY;
+ outParams.y += winOffsetY;
outParams.height = height;
- return onTop;
+ final int bottom = outParams.y + height;
+ if (bottom > displayFrameBottom) {
+ // The popup is too far down, move it back in.
+ outParams.y -= bottom - displayFrameBottom;
+ }
+
+ if (outParams.y < displayFrameTop) {
+ // The popup is too far up, move it back in and clip if
+ // it's still too large.
+ outParams.y = displayFrameTop;
+
+ final int displayFrameHeight = displayFrameBottom - displayFrameTop;
+ if (canResize && height > displayFrameHeight) {
+ outParams.height = displayFrameHeight;
+ } else {
+ fitsInDisplay = false;
+ }
+ }
+
+ outParams.y -= winOffsetY;
+
+ return fitsInDisplay;
+ }
+
+ private boolean tryFitHorizontal(@NonNull LayoutParams outParams, int xOffset, int width,
+ int anchorWidth, int drawingLocationX, int screenLocationX, int displayFrameLeft,
+ int displayFrameRight, boolean allowResize) {
+ final int anchorLeftInScreen = screenLocationX + xOffset;
+ final int spaceRight = displayFrameRight - anchorLeftInScreen;
+ if (width <= spaceRight) {
+ return true;
+ }
+
+ if (positionInDisplayHorizontal(outParams, width, drawingLocationX, screenLocationX,
+ displayFrameLeft, displayFrameRight, allowResize)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private boolean positionInDisplayHorizontal(@NonNull LayoutParams outParams, int width,
+ int drawingLocationX, int screenLocationX, int displayFrameLeft, int displayFrameRight,
+ boolean canResize) {
+ boolean fitsInDisplay = true;
+
+ // Use screen coordinates for comparison against display frame.
+ final int winOffsetX = screenLocationX - drawingLocationX;
+ outParams.x += winOffsetX;
+
+ final int right = outParams.x + width;
+ if (right > displayFrameRight) {
+ // The popup is too far right, move it back in.
+ outParams.x -= right - displayFrameRight;
+ }
+
+ if (outParams.x < displayFrameLeft) {
+ // The popup is too far left, move it back in and clip if it's
+ // still too large.
+ outParams.x = displayFrameLeft;
+
+ final int displayFrameWidth = displayFrameRight - displayFrameLeft;
+ if (canResize && width > displayFrameWidth) {
+ outParams.width = displayFrameWidth;
+ } else {
+ fitsInDisplay = false;
+ }
+ }
+
+ outParams.x -= winOffsetX;
+
+ return fitsInDisplay;
}
/**
@@ -1984,6 +2041,13 @@
update = true;
}
+ int newAccessibilityIdOfAnchor =
+ (mAnchor != null) ? mAnchor.get().getAccessibilityViewId() : -1;
+ if (newAccessibilityIdOfAnchor != p.accessibilityIdOfAnchor) {
+ p.accessibilityIdOfAnchor = newAccessibilityIdOfAnchor;
+ update = true;
+ }
+
if (update) {
setLayoutDirectionFromAnchor();
mWindowManager.updateViewLayout(mDecorView, p);
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 8bd63df..6d2cea6 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -17,6 +17,7 @@
package android.widget;
import android.annotation.ColorInt;
+import android.app.ActivityManager.StackId;
import android.app.ActivityOptions;
import android.app.ActivityThread;
import android.app.Application;
@@ -228,6 +229,11 @@
public boolean onClickHandler(View view, PendingIntent pendingIntent,
Intent fillInIntent) {
+ return onClickHandler(view, pendingIntent, fillInIntent, StackId.INVALID_STACK_ID);
+ }
+
+ public boolean onClickHandler(View view, PendingIntent pendingIntent,
+ Intent fillInIntent, int launchStackId) {
try {
// TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
Context context = view.getContext();
@@ -239,6 +245,10 @@
0, 0,
view.getMeasuredWidth(), view.getMeasuredHeight());
}
+
+ if (launchStackId != StackId.INVALID_STACK_ID) {
+ opts.setLaunchStackId(launchStackId);
+ }
context.startIntentSender(
pendingIntent.getIntentSender(), fillInIntent,
Intent.FLAG_ACTIVITY_NEW_TASK,
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 4a68d3c..3b7b16d 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -330,10 +330,6 @@
private int mCurTextColor;
private int mCurHintTextColor;
private boolean mFreezesText;
- private boolean mDispatchTemporaryDetach;
-
- /** Whether this view is temporarily detached from the parent view. */
- boolean mTemporaryDetach;
private Editable.Factory mEditableFactory = Editable.Factory.getInstance();
private Spannable.Factory mSpannableFactory = Spannable.Factory.getInstance();
@@ -2893,6 +2889,11 @@
public void setTextLocale(@NonNull Locale locale) {
mLocalesChanged = true;
mTextPaint.setTextLocale(locale);
+ if (mLayout != null) {
+ nullLayouts();
+ requestLayout();
+ invalidate();
+ }
}
/**
@@ -2909,6 +2910,11 @@
public void setTextLocales(@NonNull @Size(min=1) LocaleList locales) {
mLocalesChanged = true;
mTextPaint.setTextLocales(locales);
+ if (mLayout != null) {
+ nullLayouts();
+ requestLayout();
+ invalidate();
+ }
}
@Override
@@ -2916,6 +2922,11 @@
super.onConfigurationChanged(newConfig);
if (!mLocalesChanged) {
mTextPaint.setTextLocales(LocaleList.getDefault());
+ if (mLayout != null) {
+ nullLayouts();
+ requestLayout();
+ invalidate();
+ }
}
}
@@ -5391,8 +5402,6 @@
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- mTemporaryDetach = false;
-
if (mEditor != null) mEditor.onAttachedToWindow();
if (mPreDrawListenerDetached) {
@@ -8274,14 +8283,12 @@
newSelEnd = Selection.getSelectionEnd(buf);
}
- if (newSelStart == newSelEnd && hasTransientState()) {
- setHasTransientState(false);
- } else if (newSelStart != newSelEnd && !hasTransientState()) {
- setHasTransientState(true);
- }
-
if (mEditor != null) {
mEditor.refreshTextActionMode();
+ if (!hasSelection() && mEditor.mTextActionMode == null && hasTransientState()) {
+ // User generated selection has been removed.
+ setHasTransientState(false);
+ }
}
onSelectionChanged(newSelStart, newSelEnd);
}
@@ -8353,40 +8360,9 @@
}
}
- /**
- * @hide
- */
- @Override
- public void dispatchFinishTemporaryDetach() {
- mDispatchTemporaryDetach = true;
- super.dispatchFinishTemporaryDetach();
- mDispatchTemporaryDetach = false;
- }
-
- @Override
- public void onStartTemporaryDetach() {
- super.onStartTemporaryDetach();
- // Only track when onStartTemporaryDetach() is called directly,
- // usually because this instance is an editable field in a list
- if (!mDispatchTemporaryDetach) mTemporaryDetach = true;
-
- // Tell the editor that we are temporarily detached. It can use this to preserve
- // selection state as needed.
- if (mEditor != null) mEditor.mTemporaryDetach = true;
- }
-
- @Override
- public void onFinishTemporaryDetach() {
- super.onFinishTemporaryDetach();
- // Only track when onStartTemporaryDetach() is called directly,
- // usually because this instance is an editable field in a list
- if (!mDispatchTemporaryDetach) mTemporaryDetach = false;
- if (mEditor != null) mEditor.mTemporaryDetach = false;
- }
-
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
- if (mTemporaryDetach) {
+ if (isTemporarilyDetached()) {
// If we are temporarily in the detach state, then do nothing.
super.onFocusChanged(focused, direction, previouslyFocusedRect);
return;
@@ -9081,6 +9057,9 @@
if (mBufferType == BufferType.EDITABLE) {
info.setEditable(true);
+ if (isEnabled()) {
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_TEXT);
+ }
}
if (mEditor != null) {
@@ -9212,6 +9191,17 @@
}
}
} return false;
+ case AccessibilityNodeInfo.ACTION_SET_TEXT: {
+ if (!isEnabled() || (mBufferType != BufferType.EDITABLE)) {
+ return false;
+ }
+ CharSequence text = (arguments != null) ? arguments.getCharSequence(
+ AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE) : null;
+ setText(text);
+ if (text != null && text.length() > 0) {
+ Selection.setSelection((Spannable) mText, text.length());
+ }
+ } return true;
default: {
return super.performAccessibilityActionInternal(action, arguments);
}
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 5b0a90a..9cdb73a 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -23,6 +23,7 @@
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.annotation.StyleRes;
+import android.annotation.TestApi;
import android.app.ActionBar;
import android.content.Context;
import android.content.res.TypedArray;
@@ -976,6 +977,15 @@
}
/**
+ * @hide
+ */
+ @Nullable
+ @TestApi
+ public View getNavigationView() {
+ return mNavButtonView;
+ }
+
+ /**
* Return the Menu shown in the toolbar.
*
* <p>Applications that wish to populate the toolbar's menu can do so from here. To use
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 753c069..b7ac600 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -516,9 +516,15 @@
}
// Only show the divider if we have a title.
- final View divider;
+ View divider = null;
if (mMessage != null || mListView != null || hasCustomPanel) {
- divider = topPanel.findViewById(R.id.titleDivider);
+ if (!hasCustomPanel) {
+ divider = topPanel.findViewById(R.id.titleDividerNoCustom);
+ }
+ if (divider == null) {
+ divider = topPanel.findViewById(R.id.titleDivider);
+ }
+
} else {
divider = topPanel.findViewById(R.id.titleDividerTop);
}
@@ -526,6 +532,17 @@
if (divider != null) {
divider.setVisibility(View.VISIBLE);
}
+ } else {
+ if (contentPanel != null) {
+ final View spacer = contentPanel.findViewById(R.id.textSpacerNoTitle);
+ if (spacer != null) {
+ spacer.setVisibility(View.VISIBLE);
+ }
+ }
+ }
+
+ if (mListView instanceof RecycleListView) {
+ ((RecycleListView) mListView).setHasDecor(hasTopPanel, hasButtonPanel);
}
// Update scroll indicators as needed.
@@ -861,23 +878,34 @@
}
public static class RecycleListView extends ListView {
+ private final int mPaddingTopNoTitle;
+ private final int mPaddingBottomNoButtons;
+
boolean mRecycleOnMeasure = true;
public RecycleListView(Context context) {
- super(context);
+ this(context, null);
}
public RecycleListView(Context context, AttributeSet attrs) {
super(context, attrs);
+
+ final TypedArray ta = context.obtainStyledAttributes(
+ attrs, R.styleable.RecycleListView);
+ mPaddingBottomNoButtons = ta.getDimensionPixelOffset(
+ R.styleable.RecycleListView_paddingBottomNoButtons, -1);
+ mPaddingTopNoTitle = ta.getDimensionPixelOffset(
+ R.styleable.RecycleListView_paddingTopNoTitle, -1);
}
- public RecycleListView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- public RecycleListView(
- Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
+ public void setHasDecor(boolean hasTitle, boolean hasButtons) {
+ if (!hasButtons || !hasTitle) {
+ final int paddingLeft = getPaddingLeft();
+ final int paddingTop = hasTitle ? getPaddingTop() : mPaddingTopNoTitle;
+ final int paddingRight = getPaddingRight();
+ final int paddingBottom = hasButtons ? getPaddingBottom() : mPaddingBottomNoButtons;
+ setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
+ }
}
@Override
diff --git a/core/java/com/android/internal/app/LocaleHelper.java b/core/java/com/android/internal/app/LocaleHelper.java
index 36db5d7..a9d5113 100644
--- a/core/java/com/android/internal/app/LocaleHelper.java
+++ b/core/java/com/android/internal/app/LocaleHelper.java
@@ -219,7 +219,7 @@
public int compare(LocaleStore.LocaleInfo lhs, LocaleStore.LocaleInfo rhs) {
// We don't care about the various suggestion types, just "suggested" (!= 0)
// and "all others" (== 0)
- if (mCountryMode || (lhs.isSuggested() == rhs.isSuggested())) {
+ if (lhs.isSuggested() == rhs.isSuggested()) {
// They are in the same "bucket" (suggested / others), so we compare the text
return mCollator.compare(
removePrefixForCompare(lhs.getLocale(), lhs.getLabel(mCountryMode)),
diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java
index c4e6675..7803e52 100644
--- a/core/java/com/android/internal/app/LocaleStore.java
+++ b/core/java/com/android/internal/app/LocaleStore.java
@@ -31,8 +31,9 @@
private static boolean sFullyInitialized = false;
public static class LocaleInfo {
- private static final int SUGGESTION_TYPE_NONE = 0x00;
- private static final int SUGGESTION_TYPE_SIM = 0x01;
+ private static final int SUGGESTION_TYPE_NONE = 0;
+ private static final int SUGGESTION_TYPE_SIM = 1 << 0;
+ private static final int SUGGESTION_TYPE_CFG = 1 << 1;
private final Locale mLocale;
private final Locale mParent;
@@ -273,6 +274,22 @@
final HashSet<String> localizedLocales = new HashSet<>();
for (String localeId : LocalePicker.getSystemAssetLocales()) {
LocaleInfo li = new LocaleInfo(localeId);
+ final String country = li.getLocale().getCountry();
+ // All this is to figure out if we should suggest a country
+ if (!country.isEmpty()) {
+ LocaleInfo cachedLocale = null;
+ if (sLocaleCache.containsKey(li.getId())) { // the simple case, e.g. fr-CH
+ cachedLocale = sLocaleCache.get(li.getId());
+ } else { // e.g. zh-TW localized, zh-Hant-TW in cache
+ final String langScriptCtry = li.getLangScriptKey() + "-" + country;
+ if (sLocaleCache.containsKey(langScriptCtry)) {
+ cachedLocale = sLocaleCache.get(langScriptCtry);
+ }
+ }
+ if (cachedLocale != null) {
+ cachedLocale.mSuggestionFlags |= LocaleInfo.SUGGESTION_TYPE_CFG;
+ }
+ }
localizedLocales.add(li.getLangScriptKey());
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 0e02ed6..ff680e2 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -243,10 +243,6 @@
return;
}
- // Prevent the Resolver window from becoming the top fullscreen window and thus from taking
- // control of the system bars.
- getWindow().clearFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR);
-
final ResolverDrawerLayout rdl = (ResolverDrawerLayout) findViewById(R.id.contentPanel);
if (rdl != null) {
rdl.setOnDismissedListener(new ResolverDrawerLayout.OnDismissedListener() {
diff --git a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
index 98102ea..e2d29e3 100644
--- a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
+++ b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
@@ -49,6 +49,7 @@
private static final int TYPE_HEADER_SUGGESTED = 0;
private static final int TYPE_HEADER_ALL_OTHERS = 1;
private static final int TYPE_LOCALE = 2;
+ private static final int MIN_REGIONS_FOR_SUGGESTIONS = 6;
private ArrayList<LocaleStore.LocaleInfo> mLocaleOptions;
private ArrayList<LocaleStore.LocaleInfo> mOriginalLocaleOptions;
@@ -171,7 +172,15 @@
}
private boolean showHeaders() {
- if (mCountryMode) { // never show suggestions in country mode
+ // We don't want to show suggestions for locales with very few regions
+ // (e.g. Romanian, with 2 regions)
+ // So we put a (somewhat) arbitrary limit.
+ //
+ // The initial idea was to make that limit dependent on the screen height.
+ // But that would mean rotating the screen could make the suggestions disappear,
+ // as the number of countries that fits on the screen would be different in portrait
+ // and landscape mode.
+ if (mCountryMode && mLocaleOptions.size() < MIN_REGIONS_FOR_SUGGESTIONS) {
return false;
}
return mSuggestionCount != 0 && mSuggestionCount != mLocaleOptions.size();
diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
index 5a195cb..4260e50 100644
--- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
+++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
@@ -33,8 +33,8 @@
//
// for AppWidgetHost
//
- int[] startListening(IAppWidgetHost host, String callingPackage, int hostId,
- out List<RemoteViews> updatedViews);
+ ParceledListSlice startListening(IAppWidgetHost host, String callingPackage, int hostId,
+ in int[] appWidgetIds, out int[] updatedIds);
void stopListening(String callingPackage, int hostId);
int allocateAppWidgetId(String callingPackage, int hostId);
void deleteAppWidgetId(String callingPackage, int appWidgetId);
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 14ebe22..79138b7 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -85,6 +85,7 @@
public static final String POWER_WIFI_CONTROLLER_IDLE = "wifi.controller.idle";
public static final String POWER_WIFI_CONTROLLER_RX = "wifi.controller.rx";
public static final String POWER_WIFI_CONTROLLER_TX = "wifi.controller.tx";
+ public static final String POWER_WIFI_CONTROLLER_TX_LEVELS = "wifi.controller.tx_levels";
public static final String POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE = "wifi.controller.voltage";
public static final String POWER_BLUETOOTH_CONTROLLER_IDLE = "bluetooth.controller.idle";
@@ -287,9 +288,15 @@
};
for (int i = 0; i < configResIds.length; i++) {
+ String key = configResIdKeys[i];
+ // if we already have some of these parameters in power_profile.xml, ignore the
+ // value in config.xml
+ if ((sPowerMap.containsKey(key) && (Double) sPowerMap.get(key) > 0)) {
+ continue;
+ }
int value = resources.getInteger(configResIds[i]);
if (value > 0) {
- sPowerMap.put(configResIdKeys[i], (double) value);
+ sPowerMap.put(key, (double) value);
}
}
}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index d80b63a..0f257d7 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -24,6 +24,7 @@
import android.app.SearchManager;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.IRotationWatcher.Stub;
@@ -514,6 +515,11 @@
mDecorContentParent.setWindowTitle(title);
}
mTitle = title;
+ WindowManager.LayoutParams params = getAttributes();
+ if (!TextUtils.equals(title, params.getTitle())) {
+ params.setTitle(title);
+ dispatchWindowAttributesChanged(getAttributes());
+ }
}
@Override
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index ee73b90..bed5a2e 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -238,6 +238,14 @@
return total;
}
+ public static int[] convertToIntArray(List<Integer> list) {
+ int[] array = new int[list.size()];
+ for (int i = 0; i < list.size(); i++) {
+ array[i] = list.get(i);
+ }
+ return array;
+ }
+
/**
* Adds value to given array if not already present, providing set-like
* behavior.
diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java
index bd0e6ce..d8be9fd 100644
--- a/core/java/com/android/internal/util/AsyncChannel.java
+++ b/core/java/com/android/internal/util/AsyncChannel.java
@@ -402,7 +402,7 @@
// Initialize destination fields
mDstMessenger = dstMessenger;
-
+ linkToDeathMonitor();
if (DBG) log("connected srcHandler to the dstMessenger X");
}
@@ -844,22 +844,30 @@
msg.arg1 = status;
msg.obj = this;
msg.replyTo = mDstMessenger;
+ if (!linkToDeathMonitor()) {
+ // Override status to indicate failure
+ msg.arg1 = STATUS_BINDING_UNSUCCESSFUL;
+ }
- /*
- * Link to death only when bindService isn't used.
- */
- if (mConnection == null) {
+ mSrcHandler.sendMessage(msg);
+ }
+
+ /**
+ * Link to death monitor for destination messenger. Returns true if successfully binded to
+ * destination messenger; false otherwise.
+ */
+ private boolean linkToDeathMonitor() {
+ // Link to death only when bindService isn't used and not already linked.
+ if (mConnection == null && mDeathMonitor == null) {
mDeathMonitor = new DeathMonitor();
try {
mDstMessenger.getBinder().linkToDeath(mDeathMonitor, 0);
} catch (RemoteException e) {
mDeathMonitor = null;
- // Override status to indicate failure
- msg.arg1 = STATUS_BINDING_UNSUCCESSFUL;
+ return false;
}
}
-
- mSrcHandler.sendMessage(msg);
+ return true;
}
/**
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index 7c85246..1ead5b3 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -191,6 +191,21 @@
* Ensures that that the argument numeric value is non-negative.
*
* @param value a numeric long value
+ * @return the validated numeric value
+ * @throws IllegalArgumentException if {@code value} was negative
+ */
+ public static long checkArgumentNonnegative(final long value) {
+ if (value < 0) {
+ throw new IllegalArgumentException();
+ }
+
+ return value;
+ }
+
+ /**
+ * Ensures that that the argument numeric value is non-negative.
+ *
+ * @param value a numeric long value
* @param errorMessage the exception message to use if the check fails
* @return the validated numeric value
* @throws IllegalArgumentException if {@code value} was negative
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 9d14478..3d892af 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1099,7 +1099,8 @@
|| mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
|| mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
|| mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
- || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+ || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX
+ || mode == DevicePolicyManager.PASSWORD_QUALITY_MANAGED;
return passwordEnabled && savedPasswordExists(userId);
}
diff --git a/services/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
similarity index 94%
rename from services/core/java/com/android/server/SystemConfig.java
rename to core/java/com/android/server/SystemConfig.java
index 30e0ceb..07912cd 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -19,6 +19,7 @@
import static com.android.internal.util.ArrayUtils.appendInt;
import android.app.ActivityManager;
+import android.content.ComponentName;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageManager;
import android.os.Environment;
@@ -115,6 +116,9 @@
// These are the packages that should not run under system user
final ArraySet<String> mSystemUserBlacklistedApps = new ArraySet<>();
+ // These are the components that are enabled by default as VR mode listener services.
+ final ArraySet<ComponentName> mDefaultVrComponents = new ArraySet<>();
+
public static SystemConfig getInstance() {
synchronized (SystemConfig.class) {
if (sInstance == null) {
@@ -168,6 +172,10 @@
return mSystemUserBlacklistedApps;
}
+ public ArraySet<ComponentName> getDefaultVrComponents() {
+ return mDefaultVrComponents;
+ }
+
SystemConfig() {
// Read configuration from system
readPermissions(Environment.buildPath(
@@ -431,6 +439,19 @@
mSystemUserBlacklistedApps.add(pkgname);
}
XmlUtils.skipCurrentTag(parser);
+ } else if ("default-enabled-vr-app".equals(name) && allowAppConfigs) {
+ String pkgname = parser.getAttributeValue(null, "package");
+ String clsname = parser.getAttributeValue(null, "class");
+ if (pkgname == null) {
+ Slog.w(TAG, "<default-enabled-vr-app without package in " + permFile
+ + " at " + parser.getPositionDescription());
+ } else if (clsname == null) {
+ Slog.w(TAG, "<default-enabled-vr-app without class in " + permFile
+ + " at " + parser.getPositionDescription());
+ } else {
+ mDefaultVrComponents.add(new ComponentName(pkgname, clsname));
+ }
+ XmlUtils.skipCurrentTag(parser);
} else {
XmlUtils.skipCurrentTag(parser);
continue;
diff --git a/core/java/com/android/server/backup/ShortcutBackupHelper.java b/core/java/com/android/server/backup/ShortcutBackupHelper.java
new file mode 100644
index 0000000..0b3f2ae
--- /dev/null
+++ b/core/java/com/android/server/backup/ShortcutBackupHelper.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 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.backup;
+
+import android.app.backup.BlobBackupHelper;
+import android.content.Context;
+import android.content.pm.IShortcutService;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Slog;
+
+public class ShortcutBackupHelper extends BlobBackupHelper {
+ private static final String TAG = "ShortcutBackupAgent";
+ private static final int BLOB_VERSION = 1;
+
+ private static final String KEY_USER_FILE = "shortcutuser.xml";
+
+ public ShortcutBackupHelper() {
+ super(BLOB_VERSION, KEY_USER_FILE);
+ }
+
+ private IShortcutService getShortcutService() {
+ return IShortcutService.Stub.asInterface(
+ ServiceManager.getService(Context.SHORTCUT_SERVICE));
+ }
+
+ @Override
+ protected byte[] getBackupPayload(String key) {
+ switch (key) {
+ case KEY_USER_FILE:
+ try {
+ return getShortcutService().getBackupPayload(UserHandle.USER_SYSTEM);
+ } catch (Exception e) {
+ Slog.wtf(TAG, "Backup failed", e);
+ }
+ break;
+ default:
+ Slog.w(TAG, "Unknown key: " + key);
+ }
+ return null;
+ }
+
+ @Override
+ protected void applyRestoredPayload(String key, byte[] payload) {
+ switch (key) {
+ case KEY_USER_FILE:
+ try {
+ getShortcutService().applyRestore(payload, UserHandle.USER_SYSTEM);
+ } catch (Exception e) {
+ Slog.wtf(TAG, "Restore failed", e);
+ }
+ break;
+ default:
+ Slog.w(TAG, "Unknown key: " + key);
+ }
+ }
+}
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index 181ed51..2d12fcd 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -17,9 +17,9 @@
package com.android.server.backup;
import android.app.IWallpaperManager;
+import android.app.backup.BackupAgentHelper;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
-import android.app.backup.BackupAgentHelper;
import android.app.backup.FullBackup;
import android.app.backup.FullBackupDataOutput;
import android.app.backup.WallpaperBackupHelper;
@@ -48,6 +48,7 @@
private static final String NOTIFICATION_HELPER = "notifications";
private static final String PERMISSION_HELPER = "permissions";
private static final String USAGE_STATS_HELPER = "usage_stats";
+ private static final String SHORTCUT_MANAGER_HELPER = "shortcut_manager";
// These paths must match what the WallpaperManagerService uses. The leaf *_FILENAME
// are also used in the full-backup file format, so must not change unless steps are
@@ -100,6 +101,7 @@
addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this));
addHelper(PERMISSION_HELPER, new PermissionBackupHelper());
addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
+ addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
super.onBackup(oldState, data, newState);
}
@@ -138,6 +140,7 @@
addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this));
addHelper(PERMISSION_HELPER, new PermissionBackupHelper());
addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
+ addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
try {
super.onRestore(data, appVersionCode, newState);
diff --git a/core/java/com/android/server/net/NetlinkTracker.java b/core/java/com/android/server/net/NetlinkTracker.java
index d45982e..5b421d9 100644
--- a/core/java/com/android/server/net/NetlinkTracker.java
+++ b/core/java/com/android/server/net/NetlinkTracker.java
@@ -102,6 +102,19 @@
}
@Override
+ public void interfaceRemoved(String iface) {
+ maybeLog("interfaceRemoved", iface);
+ if (mInterfaceName.equals(iface)) {
+ // Our interface was removed. Clear our LinkProperties and tell our owner that they are
+ // now empty. Note that from the moment that the interface is removed, any further
+ // interface-specific messages (e.g., RTM_DELADDR) will not reach us, because the netd
+ // code that parses them will not be able to resolve the ifindex to an interface name.
+ clearLinkProperties();
+ mCallback.update();
+ }
+ }
+
+ @Override
public void addressUpdated(String iface, LinkAddress address) {
if (mInterfaceName.equals(iface)) {
maybeLog("addressUpdated", iface, address);
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index c6112d9..8a512a6 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -103,7 +103,6 @@
android_util_jar_StrictJarFile.cpp \
android_graphics_Canvas.cpp \
android_graphics_Picture.cpp \
- android/graphics/AvoidXfermode.cpp \
android/graphics/Bitmap.cpp \
android/graphics/BitmapFactory.cpp \
android/graphics/Camera.cpp \
diff --git a/core/jni/android/graphics/AvoidXfermode.cpp b/core/jni/android/graphics/AvoidXfermode.cpp
deleted file mode 100644
index 9ca1f26..0000000
--- a/core/jni/android/graphics/AvoidXfermode.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "AvoidXfermode.h"
-#include "SkColorPriv.h"
-#include "SkReadBuffer.h"
-#include "SkWriteBuffer.h"
-#include "SkString.h"
-
-AvoidXfermode::AvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode) {
- if (tolerance > 255) {
- tolerance = 255;
- }
- fTolerance = SkToU8(tolerance);
- fOpColor = opColor;
- fDistMul = (256 << 14) / (tolerance + 1);
- fMode = mode;
-}
-
-SkFlattenable* AvoidXfermode::CreateProc(SkReadBuffer& buffer) {
- const SkColor color = buffer.readColor();
- const unsigned tolerance = buffer.readUInt();
- const unsigned mode = buffer.readUInt();
- return Create(color, tolerance, (Mode)mode);
-}
-
-void AvoidXfermode::flatten(SkWriteBuffer& buffer) const {
- buffer.writeColor(fOpColor);
- buffer.writeUInt(fTolerance);
- buffer.writeUInt(fMode);
-}
-
-// returns 0..31
-static unsigned color_dist16(uint16_t c, unsigned r, unsigned g, unsigned b) {
- SkASSERT(r <= SK_R16_MASK);
- SkASSERT(g <= SK_G16_MASK);
- SkASSERT(b <= SK_B16_MASK);
-
- unsigned dr = SkAbs32(SkGetPackedR16(c) - r);
- unsigned dg = SkAbs32(SkGetPackedG16(c) - g) >> (SK_G16_BITS - SK_R16_BITS);
- unsigned db = SkAbs32(SkGetPackedB16(c) - b);
-
- return SkMax32(dr, SkMax32(dg, db));
-}
-
-// returns 0..255
-static unsigned color_dist32(SkPMColor c, U8CPU r, U8CPU g, U8CPU b) {
- SkASSERT(r <= 0xFF);
- SkASSERT(g <= 0xFF);
- SkASSERT(b <= 0xFF);
-
- unsigned dr = SkAbs32(SkGetPackedR32(c) - r);
- unsigned dg = SkAbs32(SkGetPackedG32(c) - g);
- unsigned db = SkAbs32(SkGetPackedB32(c) - b);
-
- return SkMax32(dr, SkMax32(dg, db));
-}
-
-static int scale_dist_14(int dist, uint32_t mul, uint32_t sub) {
- int tmp = dist * mul - sub;
- int result = (tmp + (1 << 13)) >> 14;
-
- return result;
-}
-
-static inline unsigned Accurate255To256(unsigned x) {
- return x + (x >> 7);
-}
-
-void AvoidXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count,
- const SkAlpha aa[]) const {
- unsigned opR = SkColorGetR(fOpColor);
- unsigned opG = SkColorGetG(fOpColor);
- unsigned opB = SkColorGetB(fOpColor);
- uint32_t mul = fDistMul;
- uint32_t sub = (fDistMul - (1 << 14)) << 8;
-
- int MAX, mask;
-
- if (kTargetColor_Mode == fMode) {
- mask = -1;
- MAX = 255;
- } else {
- mask = 0;
- MAX = 0;
- }
-
- for (int i = 0; i < count; i++) {
- int d = color_dist32(dst[i], opR, opG, opB);
- // now reverse d if we need to
- d = MAX + (d ^ mask) - mask;
- SkASSERT((unsigned)d <= 255);
- d = Accurate255To256(d);
-
- d = scale_dist_14(d, mul, sub);
- SkASSERT(d <= 256);
-
- if (d > 0) {
- if (aa) {
- d = SkAlphaMul(d, Accurate255To256(*aa++));
- if (0 == d) {
- continue;
- }
- }
- dst[i] = SkFourByteInterp256(src[i], dst[i], d);
- }
- }
-}
-
-static inline U16CPU SkBlend3216(SkPMColor src, U16CPU dst, unsigned scale) {
- SkASSERT(scale <= 32);
- scale <<= 3;
-
- return SkPackRGB16( SkAlphaBlend(SkPacked32ToR16(src), SkGetPackedR16(dst), scale),
- SkAlphaBlend(SkPacked32ToG16(src), SkGetPackedG16(dst), scale),
- SkAlphaBlend(SkPacked32ToB16(src), SkGetPackedB16(dst), scale));
-}
-
-void AvoidXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count,
- const SkAlpha aa[]) const {
- unsigned opR = SkColorGetR(fOpColor) >> (8 - SK_R16_BITS);
- unsigned opG = SkColorGetG(fOpColor) >> (8 - SK_G16_BITS);
- unsigned opB = SkColorGetB(fOpColor) >> (8 - SK_R16_BITS);
- uint32_t mul = fDistMul;
- uint32_t sub = (fDistMul - (1 << 14)) << SK_R16_BITS;
-
- int MAX, mask;
-
- if (kTargetColor_Mode == fMode) {
- mask = -1;
- MAX = 31;
- } else {
- mask = 0;
- MAX = 0;
- }
-
- for (int i = 0; i < count; i++) {
- int d = color_dist16(dst[i], opR, opG, opB);
- // now reverse d if we need to
- d = MAX + (d ^ mask) - mask;
- SkASSERT((unsigned)d <= 31);
- // convert from 0..31 to 0..32
- d += d >> 4;
- d = scale_dist_14(d, mul, sub);
- SkASSERT(d <= 32);
-
- if (d > 0) {
- if (aa) {
- d = SkAlphaMul(d, Accurate255To256(*aa++));
- if (0 == d) {
- continue;
- }
- }
- dst[i] = SkBlend3216(src[i], dst[i], d);
- }
- }
-}
-
-void AvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count,
- const SkAlpha aa[]) const {
-}
-
-#ifndef SK_IGNORE_TO_STRING
-void AvoidXfermode::toString(SkString* str) const {
- str->append("AvoidXfermode: opColor: ");
- str->appendHex(fOpColor);
- str->appendf("distMul: %d ", fDistMul);
-
- static const char* gModeStrings[] = { "Avoid", "Target" };
-
- str->appendf("mode: %s", gModeStrings[fMode]);
-}
-#endif
diff --git a/core/jni/android/graphics/AvoidXfermode.h b/core/jni/android/graphics/AvoidXfermode.h
deleted file mode 100644
index 8b7fb71..0000000
--- a/core/jni/android/graphics/AvoidXfermode.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef AvoidXfermode_DEFINED
-#define AvoidXfermode_DEFINED
-
-#include "SkColor.h"
-#include "SkTypes.h"
-#include "SkXfermode.h"
-
-/** \class AvoidXfermode
-
- This xfermode will draw the src everywhere except on top of the specified
- color.
-*/
-class AvoidXfermode : public SkXfermode {
-public:
- enum Mode {
- kAvoidColor_Mode, //!< draw everywhere except on the opColor
- kTargetColor_Mode //!< draw only on top of the opColor
- };
-
- /** This xfermode draws, or doesn't draw, based on the destination's
- distance from an op-color.
-
- There are two modes, and each mode interprets a tolerance value.
-
- Avoid: In this mode, drawing is allowed only on destination pixels that
- are different from the op-color.
- Tolerance near 0: avoid any colors even remotely similar to the op-color
- Tolerance near 255: avoid only colors nearly identical to the op-color
-
- Target: In this mode, drawing only occurs on destination pixels that
- are similar to the op-color
- Tolerance near 0: draw only on colors that are nearly identical to the op-color
- Tolerance near 255: draw on any colors even remotely similar to the op-color
- */
- static AvoidXfermode* Create(SkColor opColor, U8CPU tolerance, Mode mode) {
- return new AvoidXfermode(opColor, tolerance, mode);
- }
-
- // overrides from SkXfermode
- void xfer32(SkPMColor dst[], const SkPMColor src[], int count,
- const SkAlpha aa[]) const override;
- void xfer16(uint16_t dst[], const SkPMColor src[], int count,
- const SkAlpha aa[]) const override;
- void xferA8(SkAlpha dst[], const SkPMColor src[], int count,
- const SkAlpha aa[]) const override;
-
- SK_TO_STRING_OVERRIDE()
- SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(AvoidXfermode)
-
-protected:
- AvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode);
- void flatten(SkWriteBuffer&) const override;
-
-private:
- SkColor fOpColor;
- uint32_t fDistMul; // x.14 cached from fTolerance
- uint8_t fTolerance;
- Mode fMode;
-
- typedef SkXfermode INHERITED;
-};
-
-#endif
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 27b9830..22a81d4 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -251,13 +251,6 @@
void Bitmap::reconfigure(const SkImageInfo& info, size_t rowBytes,
SkColorTable* ctable) {
- {
- android::AutoMutex _lock(mLock);
- if (mPinnedRefCount) {
- ALOGW("Called reconfigure on a bitmap that is in use! This may"
- " cause graphical corruption!");
- }
- }
mPixelRef->reconfigure(info, rowBytes, ctable);
}
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 27d8fed..1844a98 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -823,7 +823,7 @@
static jfloat doRunAdvance(const Paint* paint, Typeface* typeface, const jchar buf[],
jint start, jint count, jint bufSize, jboolean isRtl, jint offset) {
int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
- if (offset == count) {
+ if (offset == start + count) {
return MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count,
bufSize, nullptr);
}
diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp
index a2662f9..b04293e 100644
--- a/core/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-#include "jni.h"
#include "GraphicsJNI.h"
+#include "jni.h"
#include "core_jni_helpers.h"
-#include "log/log.h"
+#include "PathParser.h"
#include "VectorDrawable.h"
#include <hwui/Paint.h>
@@ -27,43 +27,15 @@
using namespace uirenderer;
using namespace uirenderer::VectorDrawable;
+/**
+ * VectorDrawable's pre-draw construction.
+ */
static jlong createTree(JNIEnv*, jobject, jlong groupPtr) {
VectorDrawable::Group* rootGroup = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
VectorDrawable::Tree* tree = new VectorDrawable::Tree(rootGroup);
return reinterpret_cast<jlong>(tree);
}
-static void setTreeViewportSize(JNIEnv*, jobject, jlong treePtr,
- jfloat viewportWidth, jfloat viewportHeight) {
- VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
- tree->setViewportSize(viewportWidth, viewportHeight);
-}
-
-static jboolean setRootAlpha(JNIEnv*, jobject, jlong treePtr, jfloat alpha) {
- VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
- return tree->setRootAlpha(alpha);
-}
-
-static jfloat getRootAlpha(JNIEnv*, jobject, jlong treePtr) {
- VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
- return tree->getRootAlpha();
-}
-
-static void setAllowCaching(JNIEnv*, jobject, jlong treePtr, jboolean allowCaching) {
- VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
- tree->setAllowCaching(allowCaching);
-}
-
-static void draw(JNIEnv* env, jobject, jlong treePtr, jlong canvasPtr,
- jlong colorFilterPtr, jobject jrect, jboolean needsMirroring, jboolean canReuseCache) {
- VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
- Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
- SkRect rect;
- GraphicsJNI::jrect_to_rect(env, jrect, &rect);
- SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr);
- tree->draw(canvas, colorFilter, rect, needsMirroring, canReuseCache);
-}
-
static jlong createEmptyFullPath(JNIEnv*, jobject) {
VectorDrawable::FullPath* newPath = new VectorDrawable::FullPath();
return reinterpret_cast<jlong>(newPath);
@@ -76,46 +48,6 @@
return reinterpret_cast<jlong>(newPath);
}
-static void updateFullPathPropertiesAndStrokeStyles(JNIEnv*, jobject, jlong fullPathPtr,
- jfloat strokeWidth, jint strokeColor, jfloat strokeAlpha, jint fillColor, jfloat fillAlpha,
- jfloat trimPathStart, jfloat trimPathEnd, jfloat trimPathOffset, jfloat strokeMiterLimit,
- jint strokeLineCap, jint strokeLineJoin, jint fillType) {
- VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- fullPath->updateProperties(strokeWidth, strokeColor, strokeAlpha, fillColor, fillAlpha,
- trimPathStart, trimPathEnd, trimPathOffset, strokeMiterLimit, strokeLineCap,
- strokeLineJoin, fillType);
-}
-
-static void updateFullPathFillGradient(JNIEnv*, jobject, jlong pathPtr, jlong fillGradientPtr) {
- VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
- SkShader* fillShader = reinterpret_cast<SkShader*>(fillGradientPtr);
- path->setFillGradient(fillShader);
-}
-
-static void updateFullPathStrokeGradient(JNIEnv*, jobject, jlong pathPtr, jlong strokeGradientPtr) {
- VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
- SkShader* strokeShader = reinterpret_cast<SkShader*>(strokeGradientPtr);
- path->setStrokeGradient(strokeShader);
-}
-
-static jboolean getFullPathProperties(JNIEnv* env, jobject, jlong fullPathPtr,
- jbyteArray outProperties, jint length) {
- VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- int8_t pathProperties[length];
- bool success = fullPath->getProperties(pathProperties, length);
- env->SetByteArrayRegion(outProperties, 0, length, reinterpret_cast<int8_t*>(&pathProperties));
- return success;
-}
-
-static jboolean getGroupProperties(JNIEnv* env, jobject, jlong groupPtr,
- jfloatArray outProperties, jint length) {
- VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- float groupProperties[length];
- bool success = group->getProperties(groupProperties, length);
- env->SetFloatArrayRegion(outProperties, 0, length, reinterpret_cast<float*>(&groupProperties));
- return success;
-}
-
static jlong createEmptyClipPath(JNIEnv*, jobject) {
VectorDrawable::ClipPath* newPath = new VectorDrawable::ClipPath();
return reinterpret_cast<jlong>(newPath);
@@ -146,180 +78,265 @@
env->ReleaseStringUTFChars(nameStr, nodeName);
}
-static void updateGroupProperties(JNIEnv*, jobject, jlong groupPtr, jfloat rotate, jfloat pivotX,
- jfloat pivotY, jfloat scaleX, jfloat scaleY, jfloat translateX, jfloat translateY) {
- VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- group->updateLocalMatrix(rotate, pivotX, pivotY, scaleX, scaleY, translateX, translateY);
-}
-
static void addChild(JNIEnv*, jobject, jlong groupPtr, jlong childPtr) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
VectorDrawable::Node* child = reinterpret_cast<VectorDrawable::Node*>(childPtr);
group->addChild(child);
}
+static void setAllowCaching(JNIEnv*, jobject, jlong treePtr, jboolean allowCaching) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+ tree->setAllowCaching(allowCaching);
+}
+
+/**
+ * Draw
+ */
+static void draw(JNIEnv* env, jobject, jlong treePtr, jlong canvasPtr,
+ jlong colorFilterPtr, jobject jrect, jboolean needsMirroring, jboolean canReuseCache) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+ Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
+ SkRect rect;
+ GraphicsJNI::jrect_to_rect(env, jrect, &rect);
+ SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr);
+ tree->draw(canvas, colorFilter, rect, needsMirroring, canReuseCache);
+}
+
+/**
+ * Setters and getters for updating staging properties that can happen both pre-draw and post draw.
+ */
+static void setTreeViewportSize(JNIEnv*, jobject, jlong treePtr,
+ jfloat viewportWidth, jfloat viewportHeight) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+ tree->mutateStagingProperties()->setViewportSize(viewportWidth, viewportHeight);
+}
+
+static jboolean setRootAlpha(JNIEnv*, jobject, jlong treePtr, jfloat alpha) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+ return tree->mutateStagingProperties()->setRootAlpha(alpha);
+}
+
+static jfloat getRootAlpha(JNIEnv*, jobject, jlong treePtr) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+ return tree->stagingProperties()->getRootAlpha();
+}
+
+static void updateFullPathPropertiesAndStrokeStyles(JNIEnv*, jobject, jlong fullPathPtr,
+ jfloat strokeWidth, jint strokeColor, jfloat strokeAlpha, jint fillColor, jfloat fillAlpha,
+ jfloat trimPathStart, jfloat trimPathEnd, jfloat trimPathOffset, jfloat strokeMiterLimit,
+ jint strokeLineCap, jint strokeLineJoin, jint fillType) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ fullPath->mutateStagingProperties()->updateProperties(strokeWidth, strokeColor, strokeAlpha,
+ fillColor, fillAlpha, trimPathStart, trimPathEnd, trimPathOffset, strokeMiterLimit,
+ strokeLineCap, strokeLineJoin, fillType);
+}
+
+static void updateFullPathFillGradient(JNIEnv*, jobject, jlong pathPtr, jlong fillGradientPtr) {
+ VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
+ SkShader* fillShader = reinterpret_cast<SkShader*>(fillGradientPtr);
+ path->mutateStagingProperties()->setFillGradient(fillShader);
+}
+
+static void updateFullPathStrokeGradient(JNIEnv*, jobject, jlong pathPtr, jlong strokeGradientPtr) {
+ VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
+ SkShader* strokeShader = reinterpret_cast<SkShader*>(strokeGradientPtr);
+ path->mutateStagingProperties()->setStrokeGradient(strokeShader);
+}
+
+static jboolean getFullPathProperties(JNIEnv* env, jobject, jlong fullPathPtr,
+ jbyteArray outProperties, jint length) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ int8_t pathProperties[length];
+ bool success = fullPath->stagingProperties()->copyProperties(pathProperties, length);
+ env->SetByteArrayRegion(outProperties, 0, length, reinterpret_cast<int8_t*>(&pathProperties));
+ return success;
+}
+
+static jboolean getGroupProperties(JNIEnv* env, jobject, jlong groupPtr,
+ jfloatArray outProperties, jint length) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ float groupProperties[length];
+ bool success = group->stagingProperties()->copyProperties(groupProperties, length);
+ env->SetFloatArrayRegion(outProperties, 0, length, reinterpret_cast<float*>(&groupProperties));
+ return success;
+}
+
+static void updateGroupProperties(JNIEnv*, jobject, jlong groupPtr, jfloat rotate, jfloat pivotX,
+ jfloat pivotY, jfloat scaleX, jfloat scaleY, jfloat translateX, jfloat translateY) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ group->mutateStagingProperties()->updateProperties(rotate, pivotX, pivotY, scaleX, scaleY,
+ translateX, translateY);
+}
+
static void setPathString(JNIEnv* env, jobject, jlong pathPtr, jstring inputStr,
jint stringLength) {
VectorDrawable::Path* path = reinterpret_cast<VectorDrawable::Path*>(pathPtr);
const char* pathString = env->GetStringUTFChars(inputStr, NULL);
- path->setPath(pathString, stringLength);
+
+ PathParser::ParseResult result;
+ PathData data;
+ PathParser::getPathDataFromString(&data, &result, pathString, stringLength);
+ path->mutateStagingProperties()->setData(data);
env->ReleaseStringUTFChars(inputStr, pathString);
}
+/**
+ * Setters and getters that should only be called from animation thread for animation purpose.
+ */
static jfloat getRotation(JNIEnv*, jobject, jlong groupPtr) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- return group->getRotation();
+ return group->stagingProperties()->getRotation();
}
static void setRotation(JNIEnv*, jobject, jlong groupPtr, jfloat rotation) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- group->setRotation(rotation);
+ group->mutateStagingProperties()->setRotation(rotation);
}
static jfloat getPivotX(JNIEnv*, jobject, jlong groupPtr) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- return group->getPivotX();
+ return group->stagingProperties()->getPivotX();
}
static void setPivotX(JNIEnv*, jobject, jlong groupPtr, jfloat pivotX) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- group->setPivotX(pivotX);
+ group->mutateStagingProperties()->setPivotX(pivotX);
}
static jfloat getPivotY(JNIEnv*, jobject, jlong groupPtr) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- return group->getPivotY();
+ return group->stagingProperties()->getPivotY();
}
static void setPivotY(JNIEnv*, jobject, jlong groupPtr, jfloat pivotY) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- group->setPivotY(pivotY);
+ group->mutateStagingProperties()->setPivotY(pivotY);
}
static jfloat getScaleX(JNIEnv*, jobject, jlong groupPtr) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- return group->getScaleX();
+ return group->stagingProperties()->getScaleX();
}
static void setScaleX(JNIEnv*, jobject, jlong groupPtr, jfloat scaleX) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- group->setScaleX(scaleX);
+ group->mutateStagingProperties()->setScaleX(scaleX);
}
static jfloat getScaleY(JNIEnv*, jobject, jlong groupPtr) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- return group->getScaleY();
+ return group->stagingProperties()->getScaleY();
}
static void setScaleY(JNIEnv*, jobject, jlong groupPtr, jfloat scaleY) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- group->setScaleY(scaleY);
+ group->mutateStagingProperties()->setScaleY(scaleY);
}
static jfloat getTranslateX(JNIEnv*, jobject, jlong groupPtr) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- return group->getTranslateX();
+ return group->stagingProperties()->getTranslateX();
}
static void setTranslateX(JNIEnv*, jobject, jlong groupPtr, jfloat translateX) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- group->setTranslateX(translateX);
+ group->mutateStagingProperties()->setTranslateX(translateX);
}
static jfloat getTranslateY(JNIEnv*, jobject, jlong groupPtr) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- return group->getTranslateY();
+ return group->stagingProperties()->getTranslateY();
}
static void setTranslateY(JNIEnv*, jobject, jlong groupPtr, jfloat translateY) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- group->setTranslateY(translateY);
+ group->mutateStagingProperties()->setTranslateY(translateY);
}
static void setPathData(JNIEnv*, jobject, jlong pathPtr, jlong pathDataPtr) {
VectorDrawable::Path* path = reinterpret_cast<VectorDrawable::Path*>(pathPtr);
PathData* pathData = reinterpret_cast<PathData*>(pathDataPtr);
- path->setPathData(*pathData);
+ path->mutateStagingProperties()->setData(*pathData);
}
static jfloat getStrokeWidth(JNIEnv*, jobject, jlong fullPathPtr) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- return fullPath->getStrokeWidth();
+ return fullPath->stagingProperties()->getStrokeWidth();
}
static void setStrokeWidth(JNIEnv*, jobject, jlong fullPathPtr, jfloat strokeWidth) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- fullPath->setStrokeWidth(strokeWidth);
+ fullPath->mutateStagingProperties()->setStrokeWidth(strokeWidth);
}
static jint getStrokeColor(JNIEnv*, jobject, jlong fullPathPtr) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- return fullPath->getStrokeColor();
+ return fullPath->stagingProperties()->getStrokeColor();
}
static void setStrokeColor(JNIEnv*, jobject, jlong fullPathPtr, jint strokeColor) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- fullPath->setStrokeColor(strokeColor);
+ fullPath->mutateStagingProperties()->setStrokeColor(strokeColor);
}
static jfloat getStrokeAlpha(JNIEnv*, jobject, jlong fullPathPtr) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- return fullPath->getStrokeAlpha();
+ return fullPath->stagingProperties()->getStrokeAlpha();
}
static void setStrokeAlpha(JNIEnv*, jobject, jlong fullPathPtr, jfloat strokeAlpha) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- fullPath->setStrokeAlpha(strokeAlpha);
+ fullPath->mutateStagingProperties()->setStrokeAlpha(strokeAlpha);
}
static jint getFillColor(JNIEnv*, jobject, jlong fullPathPtr) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- return fullPath->getFillColor();
+ return fullPath->stagingProperties()->getFillColor();
}
static void setFillColor(JNIEnv*, jobject, jlong fullPathPtr, jint fillColor) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- fullPath->setFillColor(fillColor);
+ fullPath->mutateStagingProperties()->setFillColor(fillColor);
}
static jfloat getFillAlpha(JNIEnv*, jobject, jlong fullPathPtr) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- return fullPath->getFillAlpha();
+ return fullPath->stagingProperties()->getFillAlpha();
}
static void setFillAlpha(JNIEnv*, jobject, jlong fullPathPtr, jfloat fillAlpha) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- fullPath->setFillAlpha(fillAlpha);
+ fullPath->mutateStagingProperties()->setFillAlpha(fillAlpha);
}
static jfloat getTrimPathStart(JNIEnv*, jobject, jlong fullPathPtr) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- return fullPath->getTrimPathStart();
+ return fullPath->stagingProperties()->getTrimPathStart();
}
static void setTrimPathStart(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathStart) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- fullPath->setTrimPathStart(trimPathStart);
+ fullPath->mutateStagingProperties()->setTrimPathStart(trimPathStart);
}
static jfloat getTrimPathEnd(JNIEnv*, jobject, jlong fullPathPtr) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- return fullPath->getTrimPathEnd();
+ return fullPath->stagingProperties()->getTrimPathEnd();
}
static void setTrimPathEnd(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathEnd) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- fullPath->setTrimPathEnd(trimPathEnd);
+ fullPath->mutateStagingProperties()->setTrimPathEnd(trimPathEnd);
}
static jfloat getTrimPathOffset(JNIEnv*, jobject, jlong fullPathPtr) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- return fullPath->getTrimPathOffset();
+ return fullPath->stagingProperties()->getTrimPathOffset();
}
static void setTrimPathOffset(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathOffset) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- fullPath->setTrimPathOffset(trimPathOffset);
+ fullPath->mutateStagingProperties()->setTrimPathOffset(trimPathOffset);
}
static const JNINativeMethod gMethods[] = {
diff --git a/core/jni/android_hardware_location_ContextHubService.cpp b/core/jni/android_hardware_location_ContextHubService.cpp
index 8724729..80ae550 100644
--- a/core/jni/android_hardware_location_ContextHubService.cpp
+++ b/core/jni/android_hardware_location_ContextHubService.cpp
@@ -16,23 +16,39 @@
#include "context_hub.h"
+#define LOG_NDEBUG 0
+#define LOG_TAG "ContextHubService"
+
+#include <inttypes.h>
+#include <jni.h>
+#include <map>
+#include <queue>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
+#include <stdlib.h>
-#include <jni.h>
+#include <cutils/log.h>
+
#include "JNIHelp.h"
#include "core_jni_helpers.h"
-#include "stdint.h"
-#include "stdlib.h"
+
+static constexpr int OS_APP_ID=-1;
+
+static constexpr int MIN_APP_ID=1;
+static constexpr int MAX_APP_ID=128;
+
+static constexpr size_t MSG_HEADER_SIZE=4;
+static constexpr int HEADER_FIELD_MSG_TYPE=0;
+//static constexpr int HEADER_FIELD_MSG_VERSION=1;
+static constexpr int HEADER_FIELD_HUB_HANDLE=2;
+static constexpr int HEADER_FIELD_APP_INSTANCE=3;
namespace android {
namespace {
-// TODO: We should share this array_length function widely around Android
-// code.
/*
* Finds the length of a statically-sized array using template trickery that
* also prevents it from being applied to the wrong type.
@@ -64,35 +80,215 @@
jmethodID contextHubInfoSetPeakPowerDrawMw;
jmethodID contextHubInfoSetSupportedSensors;
jmethodID contextHubInfoSetMemoryRegions;
+ jmethodID contextHubInfoSetMaxPacketLenBytes;
jmethodID contextHubServiceMsgReceiptCallback;
+ jmethodID contextHubServiceAddAppInstance;
};
struct context_hub_info_s {
- int cookie;
+ uint32_t *cookies;
int numHubs;
const struct context_hub_t *hubs;
struct context_hub_module_t *contextHubModule;
};
+struct app_instance_info_s {
+ uint32_t hubHandle; // Id of the hub this app is on
+ int instanceId; // systemwide unique instance id - assigned
+ struct hub_app_info appInfo; // returned from the HAL
+ uint64_t truncName; // Possibly truncated name - logging
+};
+
struct contextHubServiceDb_s {
int initialized;
context_hub_info_s hubInfo;
jniInfo_s jniInfo;
+ std::queue<int> freeIds;
+ std::map<int, app_instance_info_s *> appInstances;
};
} // unnamed namespace
static contextHubServiceDb_s db;
-int context_hub_callback(uint32_t hub_id, const struct hub_message_t *msg,
+int context_hub_callback(uint32_t hubId, const struct hub_message_t *msg,
void *cookie);
+const context_hub_t *get_hub_info(int hubHandle) {
+ if (hubHandle >= 0 && hubHandle < db.hubInfo.numHubs) {
+ return &db.hubInfo.hubs[hubHandle];
+ }
+ return nullptr;
+}
+
+static int send_msg_to_hub(const hub_message_t *msg, int hubHandle) {
+ const context_hub_t *info = get_hub_info(hubHandle);
+
+ if (info) {
+ return db.hubInfo.contextHubModule->send_message(info->hub_id, msg);
+ } else {
+ ALOGD("%s: Hub information is null for hubHandle %d", __FUNCTION__, hubHandle);
+ return -1;
+ }
+}
+
+static int set_os_app_as_destination(hub_message_t *msg, int hubHandle) {
+ const context_hub_t *info = get_hub_info(hubHandle);
+
+ if (info) {
+ msg->app = info->os_app_name;
+ return 0;
+ } else {
+ ALOGD("%s: Hub information is null for hubHandle %d", __FUNCTION__, hubHandle);
+ return -1;
+ }
+}
+
+static int get_hub_id_for_hub_handle(int hubHandle) {
+ if (hubHandle < 0 || hubHandle >= db.hubInfo.numHubs) {
+ return -1;
+ } else {
+ return db.hubInfo.hubs[hubHandle].hub_id;
+ }
+}
+
+static int get_hub_id_for_app_instance(int id) {
+ if (db.appInstances.find(id) == db.appInstances.end()) {
+ ALOGD("%s: Cannot find app for app instance %d", __FUNCTION__, id);
+ return -1;
+ }
+
+ int hubHandle = db.appInstances[id]->hubHandle;
+
+ return db.hubInfo.hubs[hubHandle].hub_id;
+}
+
+static int set_dest_app(hub_message_t *msg, int id) {
+ if (db.appInstances.find(id) == db.appInstances.end()) {
+ ALOGD("%s: Cannod find app for app instance %d", __FUNCTION__, id);
+ return -1;
+ }
+
+ msg->app = db.appInstances[id]->appInfo.name;
+ return 0;
+}
+
+static void send_query_for_apps() {
+ hub_message_t msg;
+
+ msg.message_type = CONTEXT_HUB_QUERY_APPS;
+ msg.message_len = 0;
+
+ for (int i = 0; i < db.hubInfo.numHubs; i++ ) {
+ ALOGD("Sending query for apps to hub %d", i);
+ set_os_app_as_destination(&msg, i);
+ if (send_msg_to_hub(&msg, i) != 0) {
+ ALOGW("Could not query hub %i for apps", i);
+ }
+ }
+}
+
+static int return_id(int id) {
+ // Note : This method is not thread safe.
+ // id returned is guarenteed to be in use
+ db.freeIds.push(id);
+ return 0;
+}
+
+static int generate_id(void) {
+ // Note : This method is not thread safe.
+ int retVal = -1;
+
+ if (!db.freeIds.empty()) {
+ retVal = db.freeIds.front();
+ db.freeIds.pop();
+ }
+
+ return retVal;
+}
+
+int add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle, JNIEnv *env) {
+ // Not checking if the apps are indeed distinct
+
+ app_instance_info_s *entry;
+ void *appName;
+ hub_app_name_t *name;
+
+ assert(appInfo && appInfo->name && appInfo->name->app_name);
+
+ entry = (app_instance_info_s *) malloc(sizeof(app_instance_info_s));
+ appName = malloc(appInfo->name->app_name_len);
+ name = (hub_app_name_t *) malloc(sizeof(hub_app_name_t));
+
+ int appInstanceHandle = generate_id();
+
+ if (appInstanceHandle < 0 || !appName || !entry || !name) {
+ ALOGE("Cannot find resources to add app instance %d, %p, %p",
+ appInstanceHandle, appName, entry);
+
+ free(appName);
+ free(entry);
+ free(name);
+
+ if (appInstanceHandle >= 0) {
+ return_id(appInstanceHandle);
+ }
+
+ return -1;
+ }
+
+ memcpy(&(entry->appInfo), appInfo, sizeof(entry->appInfo));
+ memcpy(appName, appInfo->name->app_name, appInfo->name->app_name_len);
+ name->app_name = appName;
+ name->app_name_len = appInfo->name->app_name_len;
+ entry->appInfo.name = name;
+ entry->truncName = 0;
+ memcpy(&(entry->truncName), name->app_name,
+ sizeof(entry->truncName) < name->app_name_len ?
+ sizeof(entry->truncName) : name->app_name_len);
+
+ // Not checking for sanity of hubId
+ entry->hubHandle = hubHandle;
+ entry->instanceId = appInstanceHandle;
+ db.appInstances[appInstanceHandle] = entry;
+
+ // Finally - let the service know of this app instance
+ env->CallIntMethod(db.jniInfo.jContextHubService,
+ db.jniInfo.contextHubServiceAddAppInstance,
+ hubHandle, entry->instanceId, entry->truncName,
+ entry->appInfo.version);
+
+ ALOGW("Added App 0x%" PRIx64 " on hub Handle %" PRId32
+ " as appInstance %d, original name_length %" PRId32, entry->truncName,
+ entry->hubHandle, appInstanceHandle, name->app_name_len);
+
+ return appInstanceHandle;
+}
+
+int delete_app_instance(int id) {
+ if (db.appInstances.find(id) == db.appInstances.end()) {
+ return -1;
+ }
+
+ return_id(id);
+
+ if (db.appInstances[id]) {
+ // Losing the const cast below. This is intentional.
+ free((void *)db.appInstances[id]->appInfo.name->app_name);
+ free((void *)db.appInstances[id]->appInfo.name);
+ free(db.appInstances[id]);
+ db.appInstances.erase(id);
+ }
+
+ return 0;
+}
+
+
static void initContextHubService() {
int err = 0;
- db.hubInfo.hubs = NULL;
+ db.hubInfo.hubs = nullptr;
db.hubInfo.numHubs = 0;
- db.hubInfo.cookie = 0;
int i;
err = hw_get_module(CONTEXT_HUB_MODULE_ID,
@@ -103,26 +299,45 @@
strerror(-err));
}
- if (db.hubInfo.contextHubModule) {
- ALOGD("Fetching hub info");
- db.hubInfo.numHubs = db.hubInfo.contextHubModule->get_hubs(db.hubInfo.contextHubModule,
- &db.hubInfo.hubs);
+ // Prep for storing app info
+ for(i = MIN_APP_ID; i <= MAX_APP_ID; i++) {
+ db.freeIds.push(i);
+ }
- if (db.hubInfo.numHubs > 0) {
- for (i = 0; i < db.hubInfo.numHubs; i++) {
- // TODO : Event though one cookie is OK for now, lets change
- // this to be one per hub
- db.hubInfo.contextHubModule->subscribe_messages(db.hubInfo.hubs[i].hub_id,
- context_hub_callback,
- &db.hubInfo.cookie);
+ if (db.hubInfo.contextHubModule) {
+ int retNumHubs = db.hubInfo.contextHubModule->get_hubs(db.hubInfo.contextHubModule,
+ &db.hubInfo.hubs);
+ ALOGD("ContextHubModule returned %d hubs ", retNumHubs);
+ db.hubInfo.numHubs = retNumHubs;
+
+ if (db.hubInfo.numHubs > 0) {
+ db.hubInfo.numHubs = retNumHubs;
+ db.hubInfo.cookies = (uint32_t *)malloc(sizeof(uint32_t) * db.hubInfo.numHubs);
+
+ if (!db.hubInfo.cookies) {
+ ALOGW("Ran out of memory allocating cookies, bailing");
+ return;
+ }
+
+ for (i = 0; i < db.hubInfo.numHubs; i++) {
+ db.hubInfo.cookies[i] = db.hubInfo.hubs[i].hub_id;
+ if (db.hubInfo.contextHubModule->subscribe_messages(db.hubInfo.hubs[i].hub_id,
+ context_hub_callback,
+ &db.hubInfo.cookies[i]) == 0) {
+ }
+ }
}
- }
+
+ send_query_for_apps();
+ } else {
+ ALOGW("No Context Hub Module present");
}
}
static int onMessageReceipt(int *header, int headerLen, char *msg, int msgLen) {
JNIEnv *env;
- if ((db.jniInfo.vm)->AttachCurrentThread(&env, NULL) != JNI_OK) {
+
+ if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
return -1;
}
@@ -132,28 +347,131 @@
env->SetByteArrayRegion(jmsg, 0, msgLen, (jbyte *)msg);
env->SetIntArrayRegion(jheader, 0, headerLen, (jint *)header);
-
- return env->CallIntMethod(db.jniInfo.jContextHubService,
+ return (env->CallIntMethod(db.jniInfo.jContextHubService,
db.jniInfo.contextHubServiceMsgReceiptCallback,
- jheader, jmsg);
+ jheader, jmsg) != 0);
}
-int context_hub_callback(uint32_t hub_id, const struct hub_message_t *msg,
+int handle_query_apps_response(char *msg, int msgLen, uint32_t hubHandle) {
+ int i;
+ JNIEnv *env;
+ if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
+ return -1;
+ }
+
+ int numApps = msgLen/sizeof(hub_app_info);
+ hub_app_info *info = (hub_app_info *)malloc(msgLen); // handle possible alignment
+
+ if (!info) {
+ return -1;
+ }
+
+ memcpy(info, msg, msgLen);
+ for (i = 0; i < numApps; i++) {
+ add_app_instance(info, hubHandle, env);
+ info++;
+ }
+
+ free(info);
+
+ return 0;
+}
+
+
+int handle_os_message(uint32_t msgType, uint32_t hubHandle,
+ char *msg, int msgLen) {
+ int retVal;
+
+ switch(msgType) {
+ case CONTEXT_HUB_APPS_ENABLE:
+ retVal = 0;
+ break;
+
+ case CONTEXT_HUB_APPS_DISABLE:
+ retVal = 0;
+ break;
+
+ case CONTEXT_HUB_LOAD_APP:
+ retVal = 0;
+ break;
+
+ case CONTEXT_HUB_UNLOAD_APP:
+ retVal = 0;
+ break;
+
+ case CONTEXT_HUB_QUERY_APPS:
+ retVal = handle_query_apps_response(msg, msgLen, hubHandle);
+ break;
+
+ case CONTEXT_HUB_QUERY_MEMORY:
+ retVal = 0;
+ break;
+
+ case CONTEXT_HUB_LOAD_OS:
+ retVal = 0;
+ break;
+
+ default:
+ retVal = -1;
+ break;
+
+ }
+
+ return retVal;
+}
+
+static bool sanity_check_cookie(void *cookie, uint32_t hub_id) {
+ int *ptr = (int *)cookie;
+
+ if (!ptr || *ptr >= db.hubInfo.numHubs) {
+ return false;
+ }
+
+ if (db.hubInfo.hubs[*ptr].hub_id != hub_id) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+int context_hub_callback(uint32_t hubId,
+ const struct hub_message_t *msg,
void *cookie) {
- int msgHeader[4];
+ int msgHeader[MSG_HEADER_SIZE];
- msgHeader[0] = msg->message_type;
- msgHeader[1] = 0; // TODO : HAL does not have a version field
- msgHeader[2] = hub_id;
+ if (!msg) {
+ return -1;
+ }
- onMessageReceipt(msgHeader, sizeof(msgHeader), (char *)msg->message, msg->message_len); // TODO : Populate this
- return 0;
+ msgHeader[HEADER_FIELD_MSG_TYPE] = msg->message_type;
+
+ if (!sanity_check_cookie(cookie, hubId)) {
+ ALOGW("Incorrect cookie %" PRId32 " for cookie %p! Bailing",
+ hubId, cookie);
+
+ return -1;
+ }
+
+ msgHeader[HEADER_FIELD_HUB_HANDLE] = *(uint32_t*)cookie;
+
+ if (msgHeader[HEADER_FIELD_MSG_TYPE] < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE &&
+ msgHeader[HEADER_FIELD_MSG_TYPE] != 0 ) {
+ handle_os_message(msgHeader[HEADER_FIELD_MSG_TYPE],
+ msgHeader[HEADER_FIELD_HUB_HANDLE],
+ (char *)msg->message,
+ msg->message_len);
+ } else {
+ onMessageReceipt(msgHeader, sizeof(msgHeader),
+ (char *)msg->message, msg->message_len);
+ }
+
+ return 0;
}
static int init_jni(JNIEnv *env, jobject instance) {
if (env->GetJavaVM(&db.jniInfo.vm) != JNI_OK) {
- return -1;
+ return -1;
}
db.jniInfo.jContextHubService = env->NewGlobalRef(instance);
@@ -167,7 +485,6 @@
db.jniInfo.memoryRegionsClass =
env->FindClass("android/hardware/location/MemoryRegion");
- //TODO :: Add error checking
db.jniInfo.contextHubInfoCtor =
env->GetMethodID(db.jniInfo.contextHubInfoClass, "<init>", "()V");
db.jniInfo.contextHubInfoSetId =
@@ -209,6 +526,9 @@
db.jniInfo.contextHubInfoSetMemoryRegions =
env->GetMethodID(db.jniInfo.contextHubInfoClass,
"setMemoryRegions", "([Landroid/hardware/location/MemoryRegion;)V");
+ db.jniInfo.contextHubInfoSetMaxPacketLenBytes =
+ env->GetMethodID(db.jniInfo.contextHubInfoClass,
+ "setMaxPacketLenBytes", "(I)V");
db.jniInfo.contextHubServiceMsgReceiptCallback =
@@ -218,6 +538,11 @@
env->GetMethodID(db.jniInfo.contextHubInfoClass, "setName",
"(Ljava/lang/String;)V");
+ db.jniInfo.contextHubServiceAddAppInstance =
+ env->GetMethodID(db.jniInfo.contextHubServiceClass,
+ "addAppInstance", "(IIJI)I");
+
+
return 0;
}
@@ -245,20 +570,29 @@
env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPlatformVersion, hub->platform_version);
env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetToolchainVersion, hub->toolchain_version);
env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakMips, hub->peak_mips);
- env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetStoppedPowerDrawMw, hub->stopped_power_draw_mw);
- env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSleepPowerDrawMw, hub->sleep_power_draw_mw);
- env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakPowerDrawMw, hub->peak_power_draw_mw);
+ env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetStoppedPowerDrawMw,
+ hub->stopped_power_draw_mw);
+ env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSleepPowerDrawMw,
+ hub->sleep_power_draw_mw);
+ env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakPowerDrawMw,
+ hub->peak_power_draw_mw);
+ env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetMaxPacketLenBytes,
+ hub->max_supported_msg_len);
+
// TODO : jintBuf = env->NewIntArray(hub->num_connected_sensors);
- // TODO : env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors, hub->connected_sensors);
+ // TODO : env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors,
+ // hub->connected_sensors);
jintBuf = env->NewIntArray(array_length(dummyConnectedSensors));
env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors, dummyConnectedSensors);
+ env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSupportedSensors, jintBuf);
// We are not getting the memory regions from the CH Hal - change this when it is available
- jmemBuf = env->NewObjectArray(0, db.jniInfo.memoryRegionsClass, NULL);
+ jmemBuf = env->NewObjectArray(0, db.jniInfo.memoryRegionsClass, nullptr);
// Note the zero size above. We do not need to set any elements
env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetMemoryRegions, jmemBuf);
+
return jHub;
}
@@ -267,18 +601,18 @@
jobject hub;
jobjectArray retArray;
- initContextHubService();
-
if (init_jni(env, instance) < 0) {
- return NULL;
+ return nullptr;
}
- // Note : The service is clamping the number of hubs to 1
- db.hubInfo.numHubs = 1;
-
initContextHubService();
- retArray = env->NewObjectArray(db.hubInfo.numHubs, db.jniInfo.contextHubInfoClass, NULL);
+ if (db.hubInfo.numHubs > 1) {
+ ALOGW("Clamping the number of hubs to 1");
+ db.hubInfo.numHubs = 1;
+ }
+
+ retArray = env->NewObjectArray(db.hubInfo.numHubs, db.jniInfo.contextHubInfoClass, nullptr);
for(int i = 0; i < db.hubInfo.numHubs; i++) {
hub = constructJContextHubInfo(env, &db.hubInfo.hubs[i]);
@@ -290,29 +624,41 @@
static jint nativeSendMessage(JNIEnv *env, jobject instance, jintArray header_,
jbyteArray data_) {
- hub_message_t msg;
- hub_app_name_t dest;
- uint8_t os_name[8];
-
- memset(os_name, 0, sizeof(os_name));
+ jint retVal = -1; // Default to failure
jint *header = env->GetIntArrayElements(header_, 0);
- //int numHeaderElements = env->GetArrayLength(header_);
+ unsigned int numHeaderElements = env->GetArrayLength(header_);
jbyte *data = env->GetByteArrayElements(data_, 0);
int dataBufferLength = env->GetArrayLength(data_);
- /* Assume an int - thats all we understand */
- dest.app_name_len = array_length(os_name); // TODO : Check this
- //dest.app_name = &header[1];
- dest.app_name = os_name;
- msg.app = &dest;
+ if (numHeaderElements >= MSG_HEADER_SIZE) {
+ int setAddressSuccess;
+ int hubId;
+ hub_message_t msg;
- msg.message_type = header[3];
- msg.message_len = dataBufferLength;
- msg.message = data;
+ if (header[HEADER_FIELD_APP_INSTANCE] == OS_APP_ID) {
+ setAddressSuccess = (set_os_app_as_destination(&msg, header[HEADER_FIELD_HUB_HANDLE]) == 0);
+ hubId = get_hub_id_for_hub_handle(header[HEADER_FIELD_HUB_HANDLE]);
+ } else {
+ setAddressSuccess = (set_dest_app(&msg, header[HEADER_FIELD_APP_INSTANCE]) == 0);
+ hubId = get_hub_id_for_app_instance(header[HEADER_FIELD_APP_INSTANCE]);
+ }
- jint retVal = db.hubInfo.contextHubModule->send_message(header[0], &msg);
+ if (setAddressSuccess && hubId >= 0) {
+ msg.message_type = header[HEADER_FIELD_MSG_TYPE];
+ msg.message_len = dataBufferLength;
+ msg.message = data;
+ retVal = db.hubInfo.contextHubModule->send_message(hubId, &msg);
+ } else {
+ ALOGD("Could not find app instance %d on hubHandle %d, setAddress %d",
+ header[HEADER_FIELD_APP_INSTANCE],
+ header[HEADER_FIELD_HUB_HANDLE],
+ setAddressSuccess);
+ }
+ } else {
+ ALOGD("Malformed header len");
+ }
env->ReleaseIntArrayElements(header_, header, 0);
env->ReleaseByteArrayElements(data_, data, 0);
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 79b518f..27e2ee8 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -43,6 +43,54 @@
? (reinterpret_cast<RenderNode*>(renderNodePtr)->setPropertyFieldsDirty(dirtyFlag), true) \
: false)
+static JNIEnv* getenv(JavaVM* vm) {
+ JNIEnv* env;
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm);
+ }
+ return env;
+}
+
+static jmethodID gOnRenderNodeDetached;
+
+class RenderNodeContext : public VirtualLightRefBase {
+public:
+ RenderNodeContext(JNIEnv* env, jobject jobjRef) {
+ env->GetJavaVM(&mVm);
+ // This holds a weak ref because otherwise there's a cyclic global ref
+ // with this holding a strong global ref to the view which holds
+ // a strong ref to RenderNode which holds a strong ref to this.
+ mWeakRef = env->NewWeakGlobalRef(jobjRef);
+ }
+
+ virtual ~RenderNodeContext() {
+ JNIEnv* env = getenv(mVm);
+ env->DeleteWeakGlobalRef(mWeakRef);
+ }
+
+ jobject acquireLocalRef(JNIEnv* env) {
+ return env->NewLocalRef(mWeakRef);
+ }
+
+private:
+ JavaVM* mVm;
+ jweak mWeakRef;
+};
+
+// Called by ThreadedRenderer's JNI layer
+void onRenderNodeRemoved(JNIEnv* env, RenderNode* node) {
+ auto context = reinterpret_cast<RenderNodeContext*>(node->getUserContext());
+ if (!context) return;
+ jobject jnode = context->acquireLocalRef(env);
+ if (!jnode) {
+ // The owning node has been GC'd, release the context
+ node->setUserContext(nullptr);
+ return;
+ }
+ env->CallVoidMethod(jnode, gOnRenderNodeDetached);
+ env->DeleteLocalRef(jnode);
+}
+
// ----------------------------------------------------------------------------
// DisplayList view properties
// ----------------------------------------------------------------------------
@@ -59,7 +107,8 @@
return renderNode->getDebugSize();
}
-static jlong android_view_RenderNode_create(JNIEnv* env, jobject clazz, jstring name) {
+static jlong android_view_RenderNode_create(JNIEnv* env, jobject thiz,
+ jstring name) {
RenderNode* renderNode = new RenderNode();
renderNode->incStrong(0);
if (name != NULL) {
@@ -67,6 +116,7 @@
renderNode->setName(textArray);
env->ReleaseStringUTFChars(name, textArray);
}
+ renderNode->setUserContext(new RenderNodeContext(env, thiz));
return reinterpret_cast<jlong>(renderNode);
}
@@ -627,6 +677,9 @@
jclass clazz = FindClassOrDie(env, "android/view/SurfaceView");
gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz,
"updateWindowPositionRT", "(JIIII)V");
+ clazz = FindClassOrDie(env, "android/view/RenderNode");
+ gOnRenderNodeDetached = GetMethodIDOrDie(env, clazz,
+ "onRenderNodeDetached", "()V");
return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 07868c5..8019326 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -120,7 +120,13 @@
std::string mMessage;
};
-class RootRenderNode : public RenderNode, ErrorHandler {
+// TODO: Clean this up, it's a bit odd to need to call over to
+// rendernode's jni layer. Probably means RootRenderNode should be pulled
+// into HWUI with appropriate callbacks for the various JNI hooks so
+// that RenderNode's JNI layer can handle its own thing
+void onRenderNodeRemoved(JNIEnv* env, RenderNode* node);
+
+class RootRenderNode : public RenderNode, ErrorHandler, TreeObserver {
public:
RootRenderNode(JNIEnv* env) : RenderNode() {
mLooper = Looper::getForThread();
@@ -131,12 +137,15 @@
virtual ~RootRenderNode() {}
- virtual void onError(const std::string& message) {
+ virtual void onError(const std::string& message) override {
mLooper->sendMessage(new RenderingException(mVm, message), 0);
}
- virtual void prepareTree(TreeInfo& info) {
+ virtual void prepareTree(TreeInfo& info) override {
info.errorHandler = this;
+ if (info.mode == TreeInfo::MODE_FULL) {
+ info.observer = this;
+ }
// TODO: This is hacky
info.windowInsetLeft = -stagingProperties().getLeft();
info.windowInsetTop = -stagingProperties().getTop();
@@ -145,7 +154,8 @@
info.updateWindowPositions = false;
info.windowInsetLeft = 0;
info.windowInsetTop = 0;
- info.errorHandler = NULL;
+ info.errorHandler = nullptr;
+ info.observer = nullptr;
}
void sendMessage(const sp<MessageHandler>& handler) {
@@ -171,10 +181,27 @@
mPendingAnimatingRenderNodes.clear();
}
+ virtual void onMaybeRemovedFromTree(RenderNode* node) override {
+ mMaybeRemovedNodes.insert(sp<RenderNode>(node));
+ }
+
+ void processMaybeRemovedNodes(JNIEnv* env) {
+ // We can safely access mMaybeRemovedNodes here because
+ // we will only modify it in prepareTree calls that are
+ // MODE_FULL
+
+ for (auto& node : mMaybeRemovedNodes) {
+ if (node->hasParents()) continue;
+ onRenderNodeRemoved(env, node.get());
+ }
+ mMaybeRemovedNodes.clear();
+ }
+
private:
sp<Looper> mLooper;
JavaVM* mVm;
std::vector< sp<RenderNode> > mPendingAnimatingRenderNodes;
+ std::set< sp<RenderNode> > mMaybeRemovedNodes;
};
class AnimationContextBridge : public AnimationContext {
@@ -473,13 +500,16 @@
}
static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
- jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize) {
+ jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize, jlong rootNodePtr) {
LOG_ALWAYS_FATAL_IF(frameInfoSize != UI_THREAD_FRAME_INFO_SIZE,
"Mismatched size expectations, given %d expected %d",
frameInfoSize, UI_THREAD_FRAME_INFO_SIZE);
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr);
env->GetLongArrayRegion(frameInfo, 0, frameInfoSize, proxy->frameInfo());
- return proxy->syncAndDrawFrame();
+ int ret = proxy->syncAndDrawFrame();
+ rootRenderNode->processMaybeRemovedNodes(env);
+ return ret;
}
static void android_view_ThreadedRenderer_destroy(JNIEnv* env, jobject clazz,
@@ -706,7 +736,7 @@
{ "nSetup", "(JIIFII)V", (void*) android_view_ThreadedRenderer_setup },
{ "nSetLightCenter", "(JFFF)V", (void*) android_view_ThreadedRenderer_setLightCenter },
{ "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
- { "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
+ { "nSyncAndDrawFrame", "(J[JIJ)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
{ "nDestroy", "(JJ)V", (void*) android_view_ThreadedRenderer_destroy },
{ "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode },
{ "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b0fcc28..9219e81 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -348,6 +348,8 @@
<protected-broadcast android:name="android.app.action.DEVICE_OWNER_CHANGED" />
<protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_AVAILABLE" />
+ <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNAVAILABLE" />
<!-- Added in N -->
<protected-broadcast android:name="android.intent.action.ANR" />
@@ -845,14 +847,14 @@
-->
<permission android:name="android.permission.ACCESS_UCE_PRESENCE_SERVICE"
android:permissionGroup="android.permission-group.PHONE"
- android:protectionLevel="dangerous"/>
+ android:protectionLevel="signatureOrSystem"/>
<!-- @hide Allows an application to Access UCE-OPTIONS.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.ACCESS_UCE_OPTIONS_SERVICE"
android:permissionGroup="android.permission-group.PHONE"
- android:protectionLevel="dangerous"/>
+ android:protectionLevel="signatureOrSystem"/>
@@ -2004,6 +2006,11 @@
<permission android:name="android.permission.GET_ACCOUNTS_PRIVILEGED"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows but does not guarantee access to user passwords at the conclusion of add
+ account -->
+ <permission android:name="android.permission.GET_PASSWORD_PRIVILEGED"
+ android:protectionLevel="signature|privileged" />
+
<!-- @SystemApi Allows applications to RW to diagnostic resources.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.DIAGNOSTIC"
@@ -2984,6 +2991,11 @@
<permission android:name="android.permission.BIND_VR_LISTENER_SERVICE"
android:protectionLevel="signature" />
+ <!-- Allows an application to whitelist tasks during lock task mode
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.UPDATE_LOCK_TASK_PACKAGES"
+ android:protectionLevel="signature|setup" />
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"
@@ -2993,7 +3005,7 @@
android:killAfterRestore="false"
android:icon="@drawable/ic_launcher_android"
android:supportsRtl="true"
- android:theme="@style/Theme.Material.DayNight.DarkActionBar"
+ android:theme="@style/Theme.Material.Light.DarkActionBar"
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true">
<activity android:name="com.android.internal.app.ChooserActivity"
@@ -3029,7 +3041,7 @@
android:label="@string/managed_profile_label">
</activity-alias>
<activity android:name="com.android.internal.app.HeavyWeightSwitcherActivity"
- android:theme="@style/Theme.Material.DayNight.Dialog"
+ android:theme="@style/Theme.Material.Light.Dialog"
android:label="@string/heavy_weight_switcher_title"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true"
@@ -3062,7 +3074,7 @@
<activity android:name="android.accounts.ChooseAccountActivity"
android:excludeFromRecents="true"
android:exported="true"
- android:theme="@style/Theme.Material.DayNight.Dialog"
+ android:theme="@style/Theme.Material.Light.Dialog"
android:label="@string/choose_account_label"
android:process=":ui">
</activity>
@@ -3070,14 +3082,14 @@
<activity android:name="android.accounts.ChooseTypeAndAccountActivity"
android:excludeFromRecents="true"
android:exported="true"
- android:theme="@style/Theme.Material.DayNight.Dialog"
+ android:theme="@style/Theme.Material.Light.Dialog"
android:label="@string/choose_account_label"
android:process=":ui">
</activity>
<activity android:name="android.accounts.ChooseAccountTypeActivity"
android:excludeFromRecents="true"
- android:theme="@style/Theme.Material.DayNight.Dialog"
+ android:theme="@style/Theme.Material.Light.Dialog"
android:label="@string/choose_account_label"
android:process=":ui">
</activity>
@@ -3085,19 +3097,19 @@
<activity android:name="android.accounts.CantAddAccountActivity"
android:excludeFromRecents="true"
android:exported="true"
- android:theme="@style/Theme.Material.DayNight.Dialog.NoActionBar"
+ android:theme="@style/Theme.Material.Light.Dialog.NoActionBar"
android:process=":ui">
</activity>
<activity android:name="android.accounts.GrantCredentialsPermissionActivity"
android:excludeFromRecents="true"
android:exported="true"
- android:theme="@style/Theme.Material.DayNight.DialogWhenLarge"
+ android:theme="@style/Theme.Material.Light.DialogWhenLarge"
android:process=":ui">
</activity>
<activity android:name="android.content.SyncActivityTooManyDeletes"
- android:theme="@style/Theme.Material.DayNight.Dialog"
+ android:theme="@style/Theme.Material.Light.Dialog"
android:label="@string/sync_too_many_deletes"
android:process=":ui">
</activity>
@@ -3117,7 +3129,7 @@
</activity>
<activity android:name="com.android.internal.app.NetInitiatedActivity"
- android:theme="@style/Theme.Material.DayNight.Dialog.Alert"
+ android:theme="@style/Theme.Material.Light.Dialog.Alert"
android:excludeFromRecents="true"
android:process=":ui">
</activity>
@@ -3138,7 +3150,7 @@
<activity android:name="com.android.internal.app.ConfirmUserCreationActivity"
android:excludeFromRecents="true"
android:process=":ui"
- android:theme="@style/Theme.Material.DayNight.Dialog.Alert">
+ android:theme="@style/Theme.Material.Light.Dialog.Alert">
<intent-filter android:priority="1000">
<action android:name="android.os.action.CREATE_USER" />
<category android:name="android.intent.category.DEFAULT" />
@@ -3146,7 +3158,7 @@
</activity>
<activity android:name="com.android.internal.app.UnlaunchableAppActivity"
- android:theme="@style/Theme.Material.DayNight.Dialog.Alert"
+ android:theme="@style/Theme.Material.Light.Dialog.Alert"
android:excludeFromRecents="true"
android:process=":ui">
</activity>
diff --git a/core/res/res/anim/slide_in_micro.xml b/core/res/res/anim/slide_in_enter_micro.xml
similarity index 67%
rename from core/res/res/anim/slide_in_micro.xml
rename to core/res/res/anim/slide_in_enter_micro.xml
index 6320e80..14a5290 100644
--- a/core/res/res/anim/slide_in_micro.xml
+++ b/core/res/res/anim/slide_in_enter_micro.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/* //device/apps/common/res/anim/slide_in_micro.xml
**
** Copyright 2014, The Android Open Source Project
**
@@ -18,10 +17,13 @@
*/
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromXDelta="100%p" android:toXDelta="0"
- android:duration="@android:integer/config_mediumAnimTime"/>
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:zAdjustment="top">
+ <translate android:fromYDelta="5%p" android:toXDelta="0"
+ android:duration="417"
+ android:interpolator="@android:interpolator/launch_task_micro_ydelta" />
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:duration="150"
+ android:interpolator="@android:interpolator/launch_task_micro_alpha" />
</set>
diff --git a/core/res/res/anim/slide_in_exit_micro.xml b/core/res/res/anim/slide_in_exit_micro.xml
new file mode 100644
index 0000000..f0d8c0b
--- /dev/null
+++ b/core/res/res/anim/slide_in_exit_micro.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:detachWallpaper="true" android:shareInterpolator="false" android:zAdjustment="normal">
+ <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+ android:duration="417" />
+</set>
diff --git a/core/res/res/anim/slide_out_micro.xml b/core/res/res/anim/slide_out_micro.xml
index 4cb6df0..c647093 100644
--- a/core/res/res/anim/slide_out_micro.xml
+++ b/core/res/res/anim/slide_out_micro.xml
@@ -18,10 +18,13 @@
*/
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromXDelta="0" android:toXDelta="100%p"
- android:duration="@android:integer/config_mediumAnimTime"/>
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:zAdjustment="top">
+ <translate android:fromYDelta="0" android:toYDelta="5%p"
+ android:duration="250"
+ android:interpolator="@android:interpolator/fast_out_slow_in"/>
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:startOffset="100" android:duration="150"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
</set>
diff --git a/core/res/res/interpolator/launch_task_micro_alpha.xml b/core/res/res/interpolator/launch_task_micro_alpha.xml
new file mode 100644
index 0000000..41b79b5
--- /dev/null
+++ b/core/res/res/interpolator/launch_task_micro_alpha.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, 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.
+*/
+-->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0"
+ android:controlY1="0"
+ android:controlX2="0.7"
+ android:controlY2="1" />
diff --git a/core/res/res/interpolator/launch_task_micro_ydelta.xml b/core/res/res/interpolator/launch_task_micro_ydelta.xml
new file mode 100644
index 0000000..acac761
--- /dev/null
+++ b/core/res/res/interpolator/launch_task_micro_ydelta.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, 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.
+*/
+-->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0"
+ android:controlY1="0"
+ android:controlX2="0.4"
+ android:controlY2="1" />
diff --git a/core/res/res/layout/alert_dialog_material.xml b/core/res/res/layout/alert_dialog_material.xml
index 9f50937..6d33de6 100644
--- a/core/res/res/layout/alert_dialog_material.xml
+++ b/core/res/res/layout/alert_dialog_material.xml
@@ -34,7 +34,6 @@
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="@dimen/dialog_padding_top_material"
android:clipToPadding="false">
<LinearLayout
@@ -42,6 +41,12 @@
android:layout_height="wrap_content"
android:orientation="vertical">
+ <Space
+ android:id="@+id/textSpacerNoTitle"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dialog_padding_top_material" />
+
<TextView
android:id="@+id/message"
android:layout_width="match_parent"
@@ -53,7 +58,7 @@
<Space
android:id="@+id/textSpacerNoButtons"
android:visibility="gone"
- android:layout_width="0dp"
+ android:layout_width="match_parent"
android:layout_height="@dimen/dialog_padding_top_material" />
</LinearLayout>
</ScrollView>
diff --git a/core/res/res/layout/alert_dialog_title_material.xml b/core/res/res/layout/alert_dialog_title_material.xml
index 738a637..eef9585 100644
--- a/core/res/res/layout/alert_dialog_title_material.xml
+++ b/core/res/res/layout/alert_dialog_title_material.xml
@@ -21,6 +21,8 @@
android:layout_height="wrap_content"
android:orientation="vertical">
+ <!-- If the client uses a customTitle, it will be added here. -->
+
<LinearLayout
android:id="@+id/title_template"
android:layout_width="match_parent"
@@ -49,5 +51,9 @@
style="?attr/windowTitleStyle" />
</LinearLayout>
- <!-- If the client uses a customTitle, it will be added here. -->
+ <Space
+ android:id="@+id/titleDividerNoCustom"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dialog_title_divider_material" />
</LinearLayout>
diff --git a/core/res/res/layout/app_anr_dialog.xml b/core/res/res/layout/app_anr_dialog.xml
index 8bef116..5ad0f4c 100644
--- a/core/res/res/layout/app_anr_dialog.xml
+++ b/core/res/res/layout/app_anr_dialog.xml
@@ -19,7 +19,7 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="@dimen/aerr_padding_list_top"
- android:paddingBottom="@dimen/dialog_list_padding_vertical_material">
+ android:paddingBottom="@dimen/aerr_padding_list_bottom">
<Button
android:id="@+id/aerr_close"
diff --git a/core/res/res/layout/app_error_dialog.xml b/core/res/res/layout/app_error_dialog.xml
index b9531f4..7147ea2 100644
--- a/core/res/res/layout/app_error_dialog.xml
+++ b/core/res/res/layout/app_error_dialog.xml
@@ -22,7 +22,7 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="@dimen/aerr_padding_list_top"
- android:paddingBottom="@dimen/dialog_list_padding_vertical_material">
+ android:paddingBottom="@dimen/aerr_padding_list_bottom">
<Button
diff --git a/core/res/res/layout/notification_material_action_list.xml b/core/res/res/layout/notification_material_action_list.xml
index 30b5a79..ac37c4a 100644
--- a/core/res/res/layout/notification_material_action_list.xml
+++ b/core/res/res/layout/notification_material_action_list.xml
@@ -17,9 +17,7 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/actions_container"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="-16dp"
- android:layout_marginEnd="-16dp">
+ android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/actions"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/notification_template_material_big_base.xml b/core/res/res/layout/notification_template_material_big_base.xml
index d53fb5f..c54fa18 100644
--- a/core/res/res/layout/notification_template_material_big_base.xml
+++ b/core/res/res/layout/notification_template_material_big_base.xml
@@ -60,9 +60,5 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
- <include
- layout="@layout/notification_material_action_list"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- />
+ <include layout="@layout/notification_material_action_list" />
</LinearLayout>
diff --git a/core/res/res/layout/notification_template_material_big_picture.xml b/core/res/res/layout/notification_template_material_big_picture.xml
index 50aec6b..d87b9d9 100644
--- a/core/res/res/layout/notification_template_material_big_picture.xml
+++ b/core/res/res/layout/notification_template_material_big_picture.xml
@@ -27,8 +27,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="top"
- android:paddingStart="@dimen/notification_content_margin_start"
- android:paddingEnd="@dimen/notification_content_margin_end"
android:layout_marginTop="@dimen/notification_content_margin_top"
android:clipToPadding="false"
android:orientation="vertical"
@@ -37,6 +35,8 @@
android:id="@+id/notification_main_column"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/notification_content_margin_start"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
android:orientation="vertical">
<include layout="@layout/notification_template_part_line1"/>
<include layout="@layout/notification_template_progress"/>
@@ -50,14 +50,15 @@
android:layout_weight="1"
android:layout_marginTop="13dp"
android:layout_marginBottom="16dp"
+ android:layout_marginStart="@dimen/notification_content_margin_start"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
android:scaleType="centerCrop"
/>
+
<ViewStub android:layout="@layout/notification_material_reply_text"
android:id="@+id/notification_material_reply_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginStart="-16dp"
- android:layout_marginEnd="-16dp"
/>
<include layout="@layout/notification_material_action_list" />
</LinearLayout>
diff --git a/core/res/res/layout/notification_template_material_big_text.xml b/core/res/res/layout/notification_template_material_big_text.xml
index fdfefe1..3638b20 100644
--- a/core/res/res/layout/notification_template_material_big_text.xml
+++ b/core/res/res/layout/notification_template_material_big_text.xml
@@ -22,38 +22,45 @@
android:tag="bigText"
>
<include layout="@layout/notification_template_header" />
+
<LinearLayout
- android:id="@+id/notification_main_column"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top"
- android:paddingStart="@dimen/notification_content_margin_start"
- android:paddingEnd="@dimen/notification_content_margin_end"
- android:layout_marginTop="@dimen/notification_content_margin_top"
- android:clipToPadding="false"
- android:minHeight="@dimen/notification_min_content_height"
- android:orientation="vertical"
- >
- <include layout="@layout/notification_template_part_line1" />
- <include layout="@layout/notification_template_progress" />
- <com.android.internal.widget.ImageFloatingTextView android:id="@+id/big_text"
android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_marginTop="0.5dp"
- android:paddingBottom="@dimen/notification_content_margin_bottom"
- android:textAppearance="@style/TextAppearance.Material.Notification"
- android:singleLine="false"
- android:layout_weight="1"
- android:gravity="top"
- android:visibility="gone"
- />
+ android:layout_height="match_parent"
+ android:layout_gravity="top"
+ android:layout_marginTop="@dimen/notification_content_margin_top"
+ android:clipToPadding="false"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:id="@+id/notification_main_column"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:paddingStart="@dimen/notification_content_margin_start"
+ android:paddingEnd="@dimen/notification_content_margin_end"
+ android:clipToPadding="false"
+ android:minHeight="@dimen/notification_min_content_height"
+ android:orientation="vertical"
+ >
+ <include layout="@layout/notification_template_part_line1" />
+ <include layout="@layout/notification_template_progress" />
+ <com.android.internal.widget.ImageFloatingTextView android:id="@+id/big_text"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_marginTop="0.5dp"
+ android:paddingBottom="@dimen/notification_content_margin_bottom"
+ android:textAppearance="@style/TextAppearance.Material.Notification"
+ android:singleLine="false"
+ android:layout_weight="1"
+ android:gravity="top"
+ android:visibility="gone"
+ />
+ </LinearLayout>
+
<ViewStub android:layout="@layout/notification_material_reply_text"
android:id="@+id/notification_material_reply_container"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="-16dp"
- android:layout_marginEnd="-16dp"
- />
+ android:layout_height="wrap_content" />
<include layout="@layout/notification_material_action_list" />
</LinearLayout>
<include layout="@layout/notification_template_right_icon" />
diff --git a/core/res/res/layout/notification_template_material_inbox.xml b/core/res/res/layout/notification_template_material_inbox.xml
index 86902db..ce9acda 100644
--- a/core/res/res/layout/notification_template_material_inbox.xml
+++ b/core/res/res/layout/notification_template_material_inbox.xml
@@ -23,87 +23,99 @@
>
<include layout="@layout/notification_template_header" />
<LinearLayout
- android:id="@+id/notification_main_column"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top"
- android:paddingStart="@dimen/notification_content_margin_start"
- android:paddingEnd="@dimen/notification_content_margin_end"
- android:layout_marginTop="@dimen/notification_content_margin_top"
- android:minHeight="@dimen/notification_min_content_height"
- android:clipToPadding="false"
- android:orientation="vertical"
- >
- <include layout="@layout/notification_template_part_line1"
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
- <include layout="@layout/notification_template_progress"
+ android:layout_height="match_parent"
+ android:layout_gravity="top"
+ android:layout_marginTop="@dimen/notification_content_margin_top"
+ android:clipToPadding="false"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:id="@+id/notification_main_column"
android:layout_width="match_parent"
- android:layout_height="15dp"
- android:layout_marginTop="4dp"/>
- <TextView android:id="@+id/inbox_text0"
- android:textAppearance="@style/TextAppearance.Material.Notification"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:visibility="gone"
- android:layout_weight="1"
- />
- <TextView android:id="@+id/inbox_text1"
- android:textAppearance="@style/TextAppearance.Material.Notification"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:visibility="gone"
- android:layout_weight="1"
- />
- <TextView android:id="@+id/inbox_text2"
- android:textAppearance="@style/TextAppearance.Material.Notification"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:visibility="gone"
- android:layout_weight="1"
- />
- <TextView android:id="@+id/inbox_text3"
- android:textAppearance="@style/TextAppearance.Material.Notification"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:visibility="gone"
- android:layout_weight="1"
- />
- <TextView android:id="@+id/inbox_text4"
- android:textAppearance="@style/TextAppearance.Material.Notification"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:visibility="gone"
- android:layout_weight="1"
- />
- <TextView android:id="@+id/inbox_text5"
- android:textAppearance="@style/TextAppearance.Material.Notification"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:visibility="gone"
- android:layout_weight="1"
- />
- <TextView android:id="@+id/inbox_text6"
- android:textAppearance="@style/TextAppearance.Material.Notification"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:visibility="gone"
- android:layout_weight="1"
- />
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:paddingStart="@dimen/notification_content_margin_start"
+ android:paddingEnd="@dimen/notification_content_margin_end"
+ android:minHeight="@dimen/notification_min_content_height"
+ android:clipToPadding="false"
+ android:orientation="vertical"
+ >
+ <include layout="@layout/notification_template_part_line1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ <include layout="@layout/notification_template_progress"
+ android:layout_width="match_parent"
+ android:layout_height="15dp"
+ android:layout_marginTop="4dp"/>
+ <TextView android:id="@+id/inbox_text0"
+ android:textAppearance="@style/TextAppearance.Material.Notification"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:visibility="gone"
+ android:layout_weight="1"
+ />
+ <TextView android:id="@+id/inbox_text1"
+ android:textAppearance="@style/TextAppearance.Material.Notification"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:visibility="gone"
+ android:layout_weight="1"
+ />
+ <TextView android:id="@+id/inbox_text2"
+ android:textAppearance="@style/TextAppearance.Material.Notification"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:visibility="gone"
+ android:layout_weight="1"
+ />
+ <TextView android:id="@+id/inbox_text3"
+ android:textAppearance="@style/TextAppearance.Material.Notification"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:visibility="gone"
+ android:layout_weight="1"
+ />
+ <TextView android:id="@+id/inbox_text4"
+ android:textAppearance="@style/TextAppearance.Material.Notification"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:visibility="gone"
+ android:layout_weight="1"
+ />
+ <TextView android:id="@+id/inbox_text5"
+ android:textAppearance="@style/TextAppearance.Material.Notification"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:visibility="gone"
+ android:layout_weight="1"
+ />
+ <TextView android:id="@+id/inbox_text6"
+ android:textAppearance="@style/TextAppearance.Material.Notification"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:visibility="gone"
+ android:layout_weight="1"
+ />
+ </LinearLayout>
+ <ViewStub android:layout="@layout/notification_material_reply_text"
+ android:id="@+id/notification_material_reply_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
<include layout="@layout/notification_material_action_list" />
</LinearLayout>
<include layout="@layout/notification_template_right_icon" />
diff --git a/core/res/res/layout/select_dialog_material.xml b/core/res/res/layout/select_dialog_material.xml
index 19ad407..9a068f9a 100644
--- a/core/res/res/layout/select_dialog_material.xml
+++ b/core/res/res/layout/select_dialog_material.xml
@@ -30,6 +30,6 @@
android:scrollbars="vertical"
android:overScrollMode="ifContentScrolls"
android:textAlignment="viewStart"
- android:paddingTop="@dimen/dialog_list_padding_vertical_material"
- android:paddingBottom="@dimen/dialog_list_padding_vertical_material"
- android:clipToPadding="false" />
+ android:clipToPadding="false"
+ android:paddingBottomNoButtons="@dimen/dialog_list_padding_bottom_no_buttons"
+ android:paddingTopNoTitle="@dimen/dialog_list_padding_top_no_title" />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 7ca52a3..2a16a1e 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Inhoud word versteek volgens beleid"</string>
<string name="safeMode" msgid="2788228061547930246">"Veiligmodus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-stelsel"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Skakel oor na persoonlik"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Skakel oor na werk"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakte"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"in te gaan by jou kontakte"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Ligging"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"DEEL"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"WEIER"</string>
<string name="select_input_method" msgid="8547250819326693584">"Verander sleutelbord"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Ander sleutelborde"</string>
<string name="show_ime" msgid="2506087537466597099">"Hou dit op die skerm terwyl fisieke sleutelbord aktief is"</string>
<string name="hardware" msgid="194658061510127999">"Wys virtuele sleutelbord"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Stel fisieke sleutelbord op"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tik om taal en uitleg te kies"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidate"</u></string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 200ec30..0668c35 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ይዘቶች በመመሪያ ተደብቀዋል"</string>
<string name="safeMode" msgid="2788228061547930246">"የሚያስተማምን ሁነታ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android ስርዓት"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"ወደ የግል ቀይር"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"ወደ ሥራ ቀይር"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"ዕውቂያዎች"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"የእርስዎ እውቂያዎች ላይ ይድረሱባቸው"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"መገኛ አካባቢ"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"አጋራ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"አትቀበል"</string>
<string name="select_input_method" msgid="8547250819326693584">"ቁልፍ ሰሌዳ ይቀይሩ"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"ሌሎች ቁልፍ ሰሌዳዎች"</string>
<string name="show_ime" msgid="2506087537466597099">"አካላዊ የቁልፍ ሰሌዳ ገቢር ሆኖ ሳለ በማያ ገጽ ላይ አቆየው"</string>
<string name="hardware" msgid="194658061510127999">"ምናባዊ የቁልፍ ሰሌዳን አሳይ"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"አካላዊ ቁልፍ ሰሌዳን ያዋቅሩ"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ቋንቋ እና አቀማመጥን ለመምረጥ መታ ያድርጉ"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"ዕጩዎች"</u></string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index d812787..6a7c76c 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -241,10 +241,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"تم إخفاء المحتويات بواسطة السياسة"</string>
<string name="safeMode" msgid="2788228061547930246">"الوضع الآمن"</string>
<string name="android_system_label" msgid="6577375335728551336">"نظام Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"التبديل إلى الشخصي"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"التبديل إلى العمل"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"جهات الاتصال"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"الوصول إلى جهات اتصالك"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"الموقع"</string>
@@ -1095,13 +1093,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"مشاركة"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"رفض"</string>
<string name="select_input_method" msgid="8547250819326693584">"تغيير لوحة المفاتيح"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"لوحات المفاتيح الأخرى"</string>
<string name="show_ime" msgid="2506087537466597099">"استمرار عرضها على الشاشة أثناء نشاط لوحة المفاتيح الفعلية"</string>
<string name="hardware" msgid="194658061510127999">"إظهار لوحة المفاتيح الظاهرية"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"تهيئة لوحة المفاتيح الفعلية"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"انقر لاختيار لغة وتنسيق"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789 أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"العناصر المرشحة"</u></string>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 5479958..e76ce87 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Məzmun siyasət tərəfindən gizlədilib"</string>
<string name="safeMode" msgid="2788228061547930246">"Təhlükəsiz rejim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android sistemi"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Şəxsi profilə keçirin"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"İş profilinə keçirin"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktlar"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"kontaktlarınıza daxil olun"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Yer"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"PAYLAŞIN"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RƏDD EDİN"</string>
<string name="select_input_method" msgid="8547250819326693584">"Klaviaturanı dəyişin"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Digər klaviaturalar"</string>
<string name="show_ime" msgid="2506087537466597099">"Fiziki klaviatura aktiv olduğu halda ekranda saxlayın"</string>
<string name="hardware" msgid="194658061510127999">"Virtual klaviaturanı göstərin"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Fiziki klaviaturanı konfiqurasiya edin"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dil və tərtibatı seçmək üçün tıklayın"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCÇDEƏFGĞHXIİJKQLMNOÖPRSŞTUÜVYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCÇDEƏFGĞHİIJKLMNOÖPQRSŞTUÜVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"namizədlər"</u></string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 9f9b5b8..9231e9a 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -235,10 +235,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sadržaj je sakriven smernicama"</string>
<string name="safeMode" msgid="2788228061547930246">"Bezbedni režim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android sistem"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Pređi na Lični profil"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Pređi na profil za Work"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakti"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"pristupi kontaktima"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokacija"</string>
@@ -1071,13 +1069,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"DELI"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODBIJ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Promenite tastaturu"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Druge tastature"</string>
<string name="show_ime" msgid="2506087537466597099">"Zadrži ga na ekranu dok je fizička tastatura aktivna"</string>
<string name="hardware" msgid="194658061510127999">"Prikaži virtuelnu tastaturu"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurišite fizičku tastaturu"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite da biste izabrali jezik i raspored"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
diff --git a/core/res/res/values-be-rBY/strings.xml b/core/res/res/values-be-rBY/strings.xml
index 6848fda..73a8e04 100644
--- a/core/res/res/values-be-rBY/strings.xml
+++ b/core/res/res/values-be-rBY/strings.xml
@@ -237,10 +237,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Змесціва, схаванае ў адпаведнасці з палітыкай"</string>
<string name="safeMode" msgid="2788228061547930246">"Бяспечны рэжым"</string>
<string name="android_system_label" msgid="6577375335728551336">"Сістэма Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Пераключыцца на асабісты"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Пераключыцца на рабочы"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Кантакты"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"атрымліваць доступ да вашых кантактаў"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Месцазнаходжанне"</string>
@@ -1063,8 +1061,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Дазволу не патрабуецца"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"за гэта можа спаганяцца плата"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ОК"</string>
- <string name="usb_charging_notification_title" msgid="6895185153353640787">"Зарадка гэтай прылады па USB"</string>
- <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Падача сілкавання падключанай прыладзе па USB"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Па USB зараджаецца гэта прыладу"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Па USB падачецца сілкаванне падключанай прыладзе"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB для перадачы файлаў"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB для перадачы фота"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB для MIDI"</string>
@@ -1079,13 +1077,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"АБАГУЛІЦЬ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"АДХІЛІЦЬ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Змяніць клавіятуру"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Іншыя праграмныя клавіятуры"</string>
<string name="show_ime" msgid="2506087537466597099">"Захоўваць яе на экране ў той час, калі фізічная клавіятура актыўная"</string>
<string name="hardware" msgid="194658061510127999">"Паказаць віртуальную клавіятуру"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Наладжванне фізічнай клавіятуры"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Дакраніцеся, каб выбраць мову і раскладку"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГДЕЁЖЗІЙКЛМНОПРСТУЎФХЦЧШ\'ЫЬЭЮЯ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"кандыдат."</u></string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 4f8f80c..76c7002 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Съдържанието е скрито чрез правило"</string>
<string name="safeMode" msgid="2788228061547930246">"Безопасен режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Системно от Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Превключване към личния потребителски профил"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Превключване към служебния пoтребителски профил"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакти"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"има достъп до контактите ви"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Местоположение"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"СПОДЕЛЯНЕ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ОТХВЪРЛЯНЕ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Промяна на клавиатурата"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Други клавиатури"</string>
<string name="show_ime" msgid="2506087537466597099">"Показване на екрана, докато физическата клавиатура е активна"</string>
<string name="hardware" msgid="194658061510127999">"Показване на вирт. клавиатура"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Конфигуриране на физическата клавиатура"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Докоснете, за да изберете език и подредба"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index 13284cf..620e532 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"নীতির কারণে সামগ্রী লুকানো আছে"</string>
<string name="safeMode" msgid="2788228061547930246">"নিরাপদ মোড"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android সিস্টেম"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"ব্যক্তিগততে পাল্টান"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"কর্মস্থানে পাল্টান"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"পরিচিতি"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"আপনার পরিচিতিগুলিতে অ্যাক্সেস করুন"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"অবস্থান"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"শেয়ার করুন"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"অস্বীকার করুন"</string>
<string name="select_input_method" msgid="8547250819326693584">"কীবোর্ড পরিবর্তন করুন"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"অন্যান্য কীবোর্ড"</string>
<string name="show_ime" msgid="2506087537466597099">"ফিজিক্যাল কীবোর্ড সক্রিয় থাকার সময় এটিকে স্ক্রীনে রাখুন"</string>
<string name="hardware" msgid="194658061510127999">"ভার্চুয়াল কীবোর্ড দেখান"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"ফিজিক্যাল কীবোর্ড কনফিগার করুন"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ভাষা এবং লেআউট নির্বাচন করুন আলতো চাপ দিন"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"প্রার্থীরা"</u></string>
diff --git a/core/res/res/values-bs-rBA/strings.xml b/core/res/res/values-bs-rBA/strings.xml
index bbc72d5..82639af 100644
--- a/core/res/res/values-bs-rBA/strings.xml
+++ b/core/res/res/values-bs-rBA/strings.xml
@@ -235,10 +235,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sadržaj skriven u skladu sa pravilima"</string>
<string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android sistem"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Prebacite se na lični"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Prebacite se na radni"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakti"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"pristupa vašim kontaktima"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokacija"</string>
@@ -1071,13 +1069,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"PODIJELI"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODBACI"</string>
<string name="select_input_method" msgid="8547250819326693584">"Promijeni tastaturu"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Ostale tastature"</string>
<string name="show_ime" msgid="2506087537466597099">"Prikaži na ekranu dok je fizička tastatura aktivna"</string>
<string name="hardware" msgid="194658061510127999">"Prikaži virtualnu tastaturu"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfiguriraj fizičku tastaturu"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite za odabir jezika i rasporeda"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 07ba682..6fcadfa 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contingut amagat de conformitat amb la política"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode segur"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Canvia al perfil personal"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Canvia al perfil professional"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactes"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"accedir als contactes"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Ubicació"</string>
@@ -1048,7 +1046,7 @@
<string name="perm_costs_money" msgid="4902470324142151116">"pot ser que comporti càrrecs"</string>
<string name="dlg_ok" msgid="7376953167039865701">"D\'acord"</string>
<string name="usb_charging_notification_title" msgid="6895185153353640787">"L\'USB està carregant el dispositiu"</string>
- <string name="usb_supplying_notification_title" msgid="5310642257296510271">"L\'USB subministra energia al dispositiu inserit"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"L\'USB subministra energia al dispositiu connectat"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB per transferir fitxers"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB per transferir fotos"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB per a MIDI"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTEIX"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REBUTJA"</string>
<string name="select_input_method" msgid="8547250819326693584">"Canvia el teclat"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Altres teclats"</string>
<string name="show_ime" msgid="2506087537466597099">"El deixa a la pantalla mentre el teclat físic està actiu"</string>
<string name="hardware" msgid="194658061510127999">"Mostra el teclat virtual"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configura el teclat físic"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca per seleccionar l\'idioma i el disseny"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 0a9aa2b..127d38b 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -237,10 +237,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Obsah skrytý zásadami"</string>
<string name="safeMode" msgid="2788228061547930246">"Nouzový režim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Přepnout na osobní profil"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Přepnout na pracovní profil"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakty"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"přístup ke kontaktům"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Poloha"</string>
@@ -1079,13 +1077,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"SDÍLET"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODMÍTNOUT"</string>
<string name="select_input_method" msgid="8547250819326693584">"Změna klávesnice"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Další klávesnice"</string>
<string name="show_ime" msgid="2506087537466597099">"Ponechat na obrazovce, když je aktivní fyzická klávesnice"</string>
<string name="hardware" msgid="194658061510127999">"Zobrazit virtuální klávesnici"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurace fyzické klávesnice"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Klepnutím vyberte jazyk a rozvržení"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index dd2d223..407f1f8 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Indholdet er skjult af politikken"</string>
<string name="safeMode" msgid="2788228061547930246">"Sikker tilstand"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Skift til Tilpasset"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Skift til arbejde"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktpersoner"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"have adgang til dine kontaktpersoner"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Placering"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"DEL"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"AFVIS"</string>
<string name="select_input_method" msgid="8547250819326693584">"Skift tastatur"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Andre tastaturer"</string>
<string name="show_ime" msgid="2506087537466597099">"Behold den på skærmen, mens det fysiske tastatur er aktivt"</string>
<string name="hardware" msgid="194658061510127999">"Vis virtuelt tastatur"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurer fysisk tastatur"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tryk for at vælge sprog og layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index b32bea6..e539a28 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Inhalte aufgrund der Richtlinien ausgeblendet"</string>
<string name="safeMode" msgid="2788228061547930246">"Abgesicherter Modus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-System"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Zu \"Privat\" wechseln"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Zu \"Arbeit\" wechseln"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakte"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"auf Kontakte zuzugreifen"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Standort"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"TEILEN"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ABLEHNEN"</string>
<string name="select_input_method" msgid="8547250819326693584">"Tastatur ändern"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Weitere Tastaturen"</string>
<string name="show_ime" msgid="2506087537466597099">"Auf dem Display einblenden, wenn die physische Tastatur aktiv ist"</string>
<string name="hardware" msgid="194658061510127999">"Virtuelle Tastatur einblenden"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Physische Tastatur konfigurieren"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Zum Auswählen von Sprache und Layout tippen"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"Kandidaten"</u></string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 71351a3..1e891d0 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Το περιεχόμενο είναι κρυφό βάσει πολιτικής"</string>
<string name="safeMode" msgid="2788228061547930246">"Ασφαλής λειτουργία"</string>
<string name="android_system_label" msgid="6577375335728551336">"Σύστημα Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Μετάβαση σε προσωπικό προφίλ"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Μετάβαση σε προφίλ εργασίας"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Επαφές"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"πρόσβαση στις επαφές σας"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Τοποθεσία"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ΚΟΙΝΟΠΟΙΗΣΗ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ΑΠΟΡΡΙΨΗ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Αλλαγή πληκτρολογίου"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Άλλα πληκτρολόγια"</string>
<string name="show_ime" msgid="2506087537466597099">"Να παραμένει στην οθόνη όταν είναι ενεργό το φυσικό πληκτρολόγιο"</string>
<string name="hardware" msgid="194658061510127999">"Εμφάνιση εικονικού πληκτρολ."</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Διαμόρφωση φυσικού πληκτρολογίου"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Πατήστε για να επιλέξετε γλώσσα και διάταξη"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"υποψήφιοι"</u></string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index c222397..b94222c 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contents hidden by policy"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Switch to Personal"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Switch to Work"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"access your contacts"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Location"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"SHARE"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"DECLINE"</string>
<string name="select_input_method" msgid="8547250819326693584">"Change keyboard"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Other keyboards"</string>
<string name="show_ime" msgid="2506087537466597099">"Keep it on screen while physical keyboard is active"</string>
<string name="hardware" msgid="194658061510127999">"Show virtual keyboard"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configure physical keyboard"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index c222397..b94222c 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contents hidden by policy"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Switch to Personal"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Switch to Work"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"access your contacts"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Location"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"SHARE"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"DECLINE"</string>
<string name="select_input_method" msgid="8547250819326693584">"Change keyboard"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Other keyboards"</string>
<string name="show_ime" msgid="2506087537466597099">"Keep it on screen while physical keyboard is active"</string>
<string name="hardware" msgid="194658061510127999">"Show virtual keyboard"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configure physical keyboard"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index c222397..b94222c 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contents hidden by policy"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Switch to Personal"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Switch to Work"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"access your contacts"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Location"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"SHARE"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"DECLINE"</string>
<string name="select_input_method" msgid="8547250819326693584">"Change keyboard"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Other keyboards"</string>
<string name="show_ime" msgid="2506087537466597099">"Keep it on screen while physical keyboard is active"</string>
<string name="hardware" msgid="194658061510127999">"Show virtual keyboard"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configure physical keyboard"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index afd5f6c..0bfb9e0 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenido oculto debido a la política"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Cambiar al perfil personal"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Cambiar al perfil de trabajo"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactos"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"acceder a los contactos"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Ubicación"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTIR"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RECHAZAR"</string>
<string name="select_input_method" msgid="8547250819326693584">"Cambiar el teclado"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Otros teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Mantener en la pantalla cuando el teclado físico está activo"</string>
<string name="hardware" msgid="194658061510127999">"Mostrar teclado virtual"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configura el teclado físico"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Presiona para seleccionar el idioma y el diseño"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 3d5682c..99202ab 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenidos ocultos por política"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Cambiar a perfil personal"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Cambiar a perfil de trabajo"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactos"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"acceder a tus contactos"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Ubicación"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTIR"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RECHAZAR"</string>
<string name="select_input_method" msgid="8547250819326693584">"Cambiar teclado"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Otros teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Debe seguir en pantalla mientras el teclado físico esté activo"</string>
<string name="hardware" msgid="194658061510127999">"Mostrar teclado virtual"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configura el teclado físico"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca para seleccionar el idioma y el diseño"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 7b2e108..b1cc971 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sisu on eeskirjadega peidetud"</string>
<string name="safeMode" msgid="2788228061547930246">"Turvarežiim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-süsteem"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Lülita isiklikule profiilile"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Lülita tööprofiilile"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktid"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"juurdepääs kontaktidele"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Asukoht"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"JAGA"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"KEELDU"</string>
<string name="select_input_method" msgid="8547250819326693584">"Klaviatuuri muutmine"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Muud klaviatuurid"</string>
<string name="show_ime" msgid="2506087537466597099">"Hoia seda ekraanil, kui füüsiline klaviatuur on aktiivne"</string>
<string name="hardware" msgid="194658061510127999">"Virtuaalse klaviatuuri kuvam."</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Füüsilise klaviatuuri seadistamine"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Puudutage keele ja paigutuse valimiseks"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidaadid"</u></string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index 5bcaed1..a8e0285 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Gidalerro batzuk ezkutatu dira, gidalerroei jarraiki"</string>
<string name="safeMode" msgid="2788228061547930246">"Modu segurua"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android sistema"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Aldatu profil pertsonalera"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Aldatu laneko profilera"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktuak"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"kontaktuak atzitzeko"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Kokapena"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"PARTEKATU"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"BAZTERTU"</string>
<string name="select_input_method" msgid="8547250819326693584">"Aldatu teklatua"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Beste teklatu batzuk"</string>
<string name="show_ime" msgid="2506087537466597099">"Erakutsi pantailan teklatu fisikoa aktibo dagoen bitartean"</string>
<string name="hardware" msgid="194658061510127999">"Erakutsi teklatu birtuala"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfiguratu teklatua fisikoa"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Hizkuntza eta diseinua hautatzeko, sakatu hau"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"hautagaiak"</u></string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 7688af4..df9d78f 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"محتوا بر اساس خطمشی پنهان شده است"</string>
<string name="safeMode" msgid="2788228061547930246">"حالت ایمن"</string>
<string name="android_system_label" msgid="6577375335728551336">"سیستم Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"رفتن به نمایه شخصی"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"رفتن به نمایه کاری"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"مخاطبین"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"دسترسی به مخاطبین شما"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"مکان"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"اشتراکگذاری"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"نپذیرفتن"</string>
<string name="select_input_method" msgid="8547250819326693584">"تغییر صفحهکلید"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"صفحهکلیدهای دیگر"</string>
<string name="show_ime" msgid="2506087537466597099">"وقتی صفحهکلید فیزیکی فعال است این ویرایشگر را روی صفحه نگهمیدارد"</string>
<string name="hardware" msgid="194658061510127999">"نمایش صفحهکلید مجازی"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"پیکربندی صفحهکلید فیزیکی"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"برای انتخاب زبان و چیدمان ضربه بزنید"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"داوطلبین"</u></string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 9105842..c869961 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sisältö on piilotettu käytännön perusteella."</string>
<string name="safeMode" msgid="2788228061547930246">"Suojattu tila"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-järjestelmä"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Siirry henkilökohtaiseen profiiliin"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Siirry työprofiiliin"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktit"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"käyttää yhteystietoja"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Sijainti"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"JAA"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"HYLKÄÄ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Vaihda näppäimistö"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Muut näppäimistöt"</string>
<string name="show_ime" msgid="2506087537466597099">"Pidä näytöllä, kun fyysinen näppäimistö on aktiivinen."</string>
<string name="hardware" msgid="194658061510127999">"Näytä virtuaalinen näppäimistö"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Määritä fyysinen näppäimistö"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Valitse kieli ja asettelu koskettamalla."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidaatit"</u></string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 222501f..efc8af3 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenu masqué conformément aux politiques"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
<string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Passer au profil personnel"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Passer au profil professionnel"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"accéder à vos contacts"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Localisation"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"PARTAGER"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REFUSER"</string>
<string name="select_input_method" msgid="8547250819326693584">"Changer de clavier"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Autres claviers"</string>
<string name="show_ime" msgid="2506087537466597099">"Afficher lorsque le clavier physique est activé"</string>
<string name="hardware" msgid="194658061510127999">"Afficher le clavier virtuel"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configurer le clavier physique"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Touchez pour sélectionner la langue et la configuration du clavier"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 1b8e03c..4e83fa9 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenu masqué conformément aux règles"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
<string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Passer au profil personnel"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Passer au profil professionnel"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"accéder à vos contacts"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Position"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"PARTAGER"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REFUSER"</string>
<string name="select_input_method" msgid="8547250819326693584">"Changer de clavier"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Autres claviers"</string>
<string name="show_ime" msgid="2506087537466597099">"Afficher lorsque le clavier physique est activé"</string>
<string name="hardware" msgid="194658061510127999">"Afficher le clavier virtuel"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configurer le clavier physique"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Appuyer pour sélectionner la langue et la disposition"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index ae5cc61..2fa6087 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Ocultouse contido por causa da política"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Cambiar ao perfil persoal"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Cambiar ao perfil de traballo"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactos"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"acceder aos teus contactos"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Localización"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTIR"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ANULAR"</string>
<string name="select_input_method" msgid="8547250819326693584">"Cambiar teclado"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Outros teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Manteno na pantalla mentres o teclado físico estea activo"</string>
<string name="hardware" msgid="194658061510127999">"Mostrar teclado virtual"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configura o teclado físico"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca para seleccionar o idioma e o deseño"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index 0487612..0b9f4ad 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"નીતિ દ્વારા સામગ્રી છુપાવાઈ"</string>
<string name="safeMode" msgid="2788228061547930246">"સુરક્ષિત મોડ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android સિસ્ટમ"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"વ્યક્તિગત પર સ્વિચ કરો"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"કાર્ય પર સ્વિચ કરો"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"સંપર્કો"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"તમારા સંપર્કોને ઍક્સેસ કરો"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"સ્થાન"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"શેર કરો"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"નકારો"</string>
<string name="select_input_method" msgid="8547250819326693584">"કીબોર્ડ બદલો"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"અન્ય કીબોર્ડ્સ"</string>
<string name="show_ime" msgid="2506087537466597099">"જ્યારે ભૌતિક કીબોર્ડ સક્રિય હોય ત્યારે તેને સ્ક્રીન પર રાખો"</string>
<string name="hardware" msgid="194658061510127999">"વર્ચ્યુઅલ કીબોર્ડ બતાવો"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"ભૌતિક કીબોર્ડ ગોઠવો"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ભાષા અને લેઆઉટ પસંદ કરવા માટે ટૅપ કરો"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"ઉમેદવારો"</u></string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index f007f89..474e81e 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"सामग्री पॉलिसी के द्वारा छिपी हुई है"</string>
<string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android सिस्टम"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"व्यक्तिगत प्रोफ़ाइल में स्विच करें"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"कार्य प्रोफ़ाइल में स्विच करें"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"संपर्क"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"अपने संपर्कों को ऐक्सेस करें"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"स्थान"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"साझा करें"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"अस्वीकार करें"</string>
<string name="select_input_method" msgid="8547250819326693584">"कीबोर्ड बदलें"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"अन्य कीबोर्ड"</string>
<string name="show_ime" msgid="2506087537466597099">"भौतिक कीबोर्ड के सक्रिय होने के दौरान इसे स्क्रीन पर बनाए रखें"</string>
<string name="hardware" msgid="194658061510127999">"वर्चुअल कीबोर्ड दिखाएं"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"भौतिक कीबोर्ड कॉन्फ़िगर करें"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा और लेआउट चुनने के लिए टैप करें"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"उम्मीदवार"</u></string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index af8de3f..837aa56 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -235,10 +235,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sadržaj je skriven prema pravilima"</string>
<string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sustav Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Prijeđite na osobni"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Prijeđite na radni"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakti"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"pristupati vašim kontaktima"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokacija"</string>
@@ -1071,13 +1069,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"DIJELI"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODBIJ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Promjena tipkovnice"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Ostale tipkovnice"</string>
<string name="show_ime" msgid="2506087537466597099">"Zadržava se na zaslonu dok je fizička tipkovnica aktivna"</string>
<string name="hardware" msgid="194658061510127999">"Prikaži virtualnu tipkovnicu"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurirajte fizičku tipkovnicu"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite da biste odabrali jezik i raspored"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 6ae5120..0c4705d 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"A tartalom irányelv miatt elrejtve"</string>
<string name="safeMode" msgid="2788228061547930246">"Biztonsági üzemmód"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android rendszer"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Átváltás személyes profilra"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Átváltás munkaprofilra"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Névjegyek"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"hozzáférés a névjegyekhez"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Helyadatok"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"MEGOSZTÁS"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ELUTASÍTÁS"</string>
<string name="select_input_method" msgid="8547250819326693584">"Billentyűzet megváltoztatása"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Más billentyűzetek"</string>
<string name="show_ime" msgid="2506087537466597099">"Maradjon a képernyőn, amíg a billentyűzet aktív"</string>
<string name="hardware" msgid="194658061510127999">"Virtuális billentyűzet"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Állítsa be a fizikai billentyűzetet"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Koppintson a nyelv és a billentyűzetkiosztás kiválasztásához"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"jelöltek"</u></string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 1a4a2eb..4be90da 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Բովանդակությունը թաքցվել է ըստ քաղաքականության"</string>
<string name="safeMode" msgid="2788228061547930246">"Անվտանգ ռեժիմ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android համակարգ"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Անցնել անհատական պրոֆիլին"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Անցնել աշխատանքային պրոֆիլին"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Կոնտակտներ"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"կոնտակտների հասանելիություն"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Տեղադրություն"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ՏՐԱՄԱԴՐԵԼ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ՄԵՐԺԵԼ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Փոխել ստեղնաշարը"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Այլ ստեղնաշարեր"</string>
<string name="show_ime" msgid="2506087537466597099">"Պահել էկրանին մինչդեռ ֆիզիկական ստեղնաշարն ակտիվ է"</string>
<string name="hardware" msgid="194658061510127999">"Ցույց տալ վիրտուալ ստեղնաշարը"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Կազմաձևեք ֆիզիկական ստեղնաշարը"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Հպեք՝ լեզուն և դասավորությունն ընտրելու համար"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՈՒՓՔԵւՕՖ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"թեկնածուները"</u></string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 480a845..7218617 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Konten disembunyikan menurut kebijakan"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode aman"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Beralih ke Pribadi"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Beralih ke Kantor"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontak"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"mengakses kontak"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokasi"</string>
@@ -1047,8 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Tidak perlu izin"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"ini mungkin tidak gratis"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Oke"</string>
- <string name="usb_charging_notification_title" msgid="6895185153353640787">"Mengisi daya perangkat ini melalui USB"</string>
- <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Menyuplai daya melalui USB ke perangkat yang terpasang"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Isi daya perangkat ini melalui USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Suplai daya melalui USB ke perangkat yang terpasang"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB untuk transfer file"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB untuk transfer foto"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB untuk MIDI"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"BAGIKAN"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"TOLAK"</string>
<string name="select_input_method" msgid="8547250819326693584">"Ubah keyboard"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Keyboard lainnya"</string>
<string name="show_ime" msgid="2506087537466597099">"Pertahankan di layar jika keyboard fisik masih aktif"</string>
<string name="hardware" msgid="194658061510127999">"Tampilkan keyboard virtual"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Mengonfigurasi keyboard fisik"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ketuk untuk memilih bahasa dan tata letak"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index ce00b09..cebc4cc 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Efni falið með reglu"</string>
<string name="safeMode" msgid="2788228061547930246">"Örugg stilling"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android kerfið"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Skipta yfir í persónulegt snið"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Skipta yfir í vinnusnið"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Tengiliðir"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"fá aðgang að tengiliðunum þínum"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Staðsetning"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"DEILA"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"HAFNA"</string>
<string name="select_input_method" msgid="8547250819326693584">"Skipta um lyklaborð"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Önnur lyklaborð"</string>
<string name="show_ime" msgid="2506087537466597099">"Haltu því á skjánum meðan vélbúnaðarlyklaborðið er virkt"</string>
<string name="hardware" msgid="194658061510127999">"Sýna sýndarlyklaborð"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Stilla vélbúnaðarlyklaborð"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ýttu til að velja tungumál og útlit"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCDÐEÉFGHIÍJKLMNOÓPQRSTUÚVWXYÝZÞÆÖ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AÁBCDÐEÉFGHIÍJKLMNOÓPQRSTUÚVWXYÝZÞÆÖ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"möguleikar"</u></string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 19fcf55..2a73990 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenuti nascosti in base alle norme"</string>
<string name="safeMode" msgid="2788228061547930246">"Modalità provvisoria"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Passa al profilo personale"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Passa al profilo di lavoro"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contatti"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"accedere ai contatti"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Posizione"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"CONDIVIDI"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RIFIUTO"</string>
<string name="select_input_method" msgid="8547250819326693584">"Cambia tastiera"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Altre tastiere"</string>
<string name="show_ime" msgid="2506087537466597099">"Tieni sullo schermo quando è attiva la tastiera fisica"</string>
<string name="hardware" msgid="194658061510127999">"Mostra tastiera virtuale"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configura la tastiera fisica"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tocca per selezionare la lingua e il layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidati"</u></string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 41acce9..80435b6 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -237,10 +237,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"התוכן מוסתר על ידי המדיניות"</string>
<string name="safeMode" msgid="2788228061547930246">"מצב בטוח"</string>
<string name="android_system_label" msgid="6577375335728551336">"מערכת Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"עבור ל\'אישי\'"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"עבור ל\'עבודה\'"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"אנשי קשר"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"גישה אל אנשי הקשר"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"מיקום"</string>
@@ -1079,13 +1077,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"שתף"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"דחה"</string>
<string name="select_input_method" msgid="8547250819326693584">"שינוי מקלדת"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"מקלדות אחרות"</string>
<string name="show_ime" msgid="2506087537466597099">"השאר אותו במסך בזמן שהמקלדת הפיזית פעילה"</string>
<string name="hardware" msgid="194658061510127999">"הצג מקלדת וירטואלית"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"הגדרת מקלדת פיזית"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"הקש כדי לבחור שפה ופריסה"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"מועמדים"</u></string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index dff30b4..394775f 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ポリシーによって非表示になっているコンテンツ"</string>
<string name="safeMode" msgid="2788228061547930246">"セーフモード"</string>
<string name="android_system_label" msgid="6577375335728551336">"Androidシステム"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"個人用に切り替える"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"仕事用に切り替える"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"連絡先"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"連絡先へのアクセス"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"位置情報"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"共有する"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"共有しない"</string>
<string name="select_input_method" msgid="8547250819326693584">"キーボードの変更"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"その他のキーボード"</string>
<string name="show_ime" msgid="2506087537466597099">"物理キーボードが有効になっている間は、画面に表示されます"</string>
<string name="hardware" msgid="194658061510127999">"仮想キーボードの表示"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"物理キーボードの設定"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"タップして言語とレイアウトを選択してください"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"候補"</u></string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index eaed9dd9..fcc56da 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"შიგთავსი დამალულია წესების შესაბამისად"</string>
<string name="safeMode" msgid="2788228061547930246">"უსაფრთხო რეჟიმი"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-ის სისტემა"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"პირად პროფილზე გადართვა"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"სამსახურის პროფილზე გადართვა"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"კონტაქტები"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"თქვენს კონტაქტებზე წვდომა"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"მდებარეობა"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"გაზიარება"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"უარყოფა"</string>
<string name="select_input_method" msgid="8547250819326693584">"კლავიატურის შეცვლა"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"სხვა კლავიატურები"</string>
<string name="show_ime" msgid="2506087537466597099">"აქტიური ფიზიკური კლავიატურისას ეკრანზე შენარჩუნება"</string>
<string name="hardware" msgid="194658061510127999">"ვირტუალური კლავიატურის ჩვენება"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"მოახდინეთ ფიზიკური კლავიატურის კონფიგურაცია"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"შეეხეთ ენისა და განლაგების ასარჩევად"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"კანდიდატები"</u></string>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index aecf49f..6eaa770 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Мазмұн саясатқа сай жасырылған"</string>
<string name="safeMode" msgid="2788228061547930246">"Қауіпсіз режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android жүйесі"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Жекеге ауысу"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Жұмысқа ауысу"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Контактілер"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"контактілерге кіру"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Орын"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"БӨЛІСУ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ҚАБЫЛДАМАУ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Пернетақтаны өзгерту"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Басқа пернетақталар"</string>
<string name="show_ime" msgid="2506087537466597099">"Физикалық пернетақта белсенді кезде оны экранда ұстау"</string>
<string name="hardware" msgid="194658061510127999">"Виртуалды пернетақтаны көрсету"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Физикалық пернетақтаны конфигурациялау"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Тіл мен пернетақта схемасын таңдау үшін түртіңіз"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"үміткерлер"</u></string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index fb80d6e..30d3c0a 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"មាតិកាត្រូវបានលាក់ដោយផ្អែកលើគោលការណ៍"</string>
<string name="safeMode" msgid="2788228061547930246">"របៀបសុវត្ថិភាព"</string>
<string name="android_system_label" msgid="6577375335728551336">"ប្រព័ន្ធ Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"ប្តូរទៅផ្ទាល់ខ្លួន"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"ប្តូរទៅការងារ"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"ទំនាក់ទំនង"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"ចូលប្រើទំនាក់ទំនងរបស់អ្នក"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"ទីតាំង"</string>
@@ -1065,13 +1063,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ចែករំលែក"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"បដិសេធ"</string>
<string name="select_input_method" msgid="8547250819326693584">"ប្ដូរក្ដារចុច"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"ក្តារចុចផ្សេងទៀត"</string>
<string name="show_ime" msgid="2506087537466597099">"ទុកវានៅលើអេក្រង់ខណៈពេលក្តារចុចពិតប្រាកដកំពុងសកម្ម"</string>
<string name="hardware" msgid="194658061510127999">"បង្ហាញក្ដារចុចនិម្មិត"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"កំណត់រចនាសម្ព័ន្ធក្តារចុចពិតប្រាកដ"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ប៉ះដើម្បីជ្រើសភាសា និងប្លង់"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"បេក្ខជន"</u></string>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index f2e5024..087b399 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ನೀತಿಯಿಂದ ಮರೆಮಾಡಲಾಗಿರುವ ವಿಷಯಗಳು"</string>
<string name="safeMode" msgid="2788228061547930246">"ಸುರಕ್ಷಿತ ಮೋಡ್"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android ಸಿಸ್ಟಂ"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"ವೈಯಕ್ತಿಕಗೆ ಬದಲಿಸಿ"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"ಕೆಲಸಕ್ಕೆ ಬದಲಿಸು"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"ಸಂಪರ್ಕಗಳು"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"ನಿಮ್ಮ ಸಂಪರ್ಕಗಳನ್ನು ಪ್ರವೇಶಿಸಲು"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"ಸ್ಥಳ"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ಹಂಚಿಕೊಳ್ಳಿ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ನಿರಾಕರಿಸು"</string>
<string name="select_input_method" msgid="8547250819326693584">"ಕೀಬೋರ್ಡ್ ಬದಲಿಸಿ"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"ಇತರೆ ಕೀಬೋರ್ಡ್ಗಳು"</string>
<string name="show_ime" msgid="2506087537466597099">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್ ಸಕ್ರಿಯವಾಗಿರುವಾಗ ಅದನ್ನು ಪರದೆಯ ಮೇಲೆ ಇರಿಸಿಕೊಳ್ಳಿ"</string>
<string name="hardware" msgid="194658061510127999">"ವರ್ಚ್ಯುಯಲ್ ಕೀಬೋರ್ಡ್ ತೋರಿಸು"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್ ಕಾನ್ಫಿಗರ್ ಮಾಡಿ"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ಭಾಷೆ ಮತ್ತು ವಿನ್ಯಾಸವನ್ನು ಆಯ್ಕೆ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"ಅಭ್ಯರ್ಥಿಗಳು"</u></string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index dc69ee9..52de5ba 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"콘텐츠가 정책에 의해 숨겨졌습니다."</string>
<string name="safeMode" msgid="2788228061547930246">"안전 모드"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 시스템"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"개인으로 전환"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"직장으로 전환"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"주소록"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"주소록에 접근할 수 있도록"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"위치"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"공유"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"거부"</string>
<string name="select_input_method" msgid="8547250819326693584">"키보드 변경"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"기타 키보드"</string>
<string name="show_ime" msgid="2506087537466597099">"물리적 키보드가 활성 상태인 경우 화면에 켜 둠"</string>
<string name="hardware" msgid="194658061510127999">"가상 키보드 표시"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"물리적 키보드 설정"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"탭하여 언어와 레이아웃을 선택하세요."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"가능한 원인"</u></string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 03951a4..34cc7e5 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Тийиштүү саясат боюнча жашырылган мазмундар"</string>
<string name="safeMode" msgid="2788228061547930246">"Коопсуз режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android Тутуму"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Жеке профилге которулуу"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Жумуш профилине которулуу"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Байланыштар"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"байланыштарыңызга уруксат"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Жайгашкан жер"</string>
@@ -1064,13 +1062,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"БӨЛҮШҮҮ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ЧЕТКЕ КАГУУ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Баскычтопту өзгөртүү"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Башка баскычтоптор"</string>
<string name="show_ime" msgid="2506087537466597099">"Баскычтоп иштетилгенде экранда көрүнүп турсун"</string>
<string name="hardware" msgid="194658061510127999">"Виртуалдык баскычтоп"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Аппараттык баскычтопту конфигурациялоо"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Тил жана калып тандоо үчүн таптап коюңуз"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"талапкерлер"</u></string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index f64f8df..ea62f9b 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ເນື້ອຫາຖືກເຊື່ອງຕາມນະໂຍບາຍ"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"ລະບົບ Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"ສະລັບໄປໂປຣໄຟລ໌ສ່ວນຕົວ"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"ສະລັບໄປໂປຣໄຟລ໌ວຽ."</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"ລາຍຊື່"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"ເຂົ້າຫາລາຍຊື່ຂອງທ່ານ"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"ສະຖານທີ່"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ແບ່ງປັນ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ປະຕິເສດ"</string>
<string name="select_input_method" msgid="8547250819326693584">"ປ່ຽນແປ້ນພິມ"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"ແປ້ນພິມອື່ນໆ"</string>
<string name="show_ime" msgid="2506087537466597099">"ເປີດໃຊ້ໃຫ້ມັນຢູ່ໃນໜ້າຈໍໃນຂະນະທີ່ໃຊ້ແປ້ນພິມພາຍນອກຢູ່"</string>
<string name="hardware" msgid="194658061510127999">"ສະແດງແປ້ນພິມສະເໝືອນ"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"ຕັ້ງຄ່າແປ້ນພິມພາຍນອກ"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ແຕະເພື່ອເລືອກພາສາ ແລະ ໂຄງແປ້ນພິມ"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"ຕົວເລືອກ"</u></string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 517a069..3e815ec 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -237,10 +237,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Turinys paslėptas vadovaujantis politika"</string>
<string name="safeMode" msgid="2788228061547930246">"Saugos režimas"</string>
<string name="android_system_label" msgid="6577375335728551336">"„Android“ sistema"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Perjungti į asmeninį režimą"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Perjungti į darbo režimą"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktai"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"pasiekti kontaktus"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Vietovė"</string>
@@ -1079,13 +1077,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"BENDRINTI"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ATMESTI"</string>
<string name="select_input_method" msgid="8547250819326693584">"Klaviatūros keitimas"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Kitos klaviatūros"</string>
<string name="show_ime" msgid="2506087537466597099">"Palikti ekrane, kol fizinė klaviatūra aktyvi"</string>
<string name="hardware" msgid="194658061510127999">"Rodyti virtualiąją klaviatūrą"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Fizinės klaviatūros konfigūravimas"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Palieskite, kad pasirinktumėte kalbą ir išdėstymą"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidatai"</u></string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 8d8f99b..56001fc 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -235,10 +235,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Saskaņā ar politiku saturs ir paslēpts."</string>
<string name="safeMode" msgid="2788228061547930246">"Drošais režīms"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android sistēma"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Pārslēgt personīgo profilu"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Pārslēgt darba profilu"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktpersonas"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"piekļūt jūsu kontaktpersonu datiem"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Atrašanās vieta"</string>
@@ -1071,13 +1069,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"KOPĪGOT"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"NORAIDĪT"</string>
<string name="select_input_method" msgid="8547250819326693584">"Tastatūras maiņa"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Citas tastatūras"</string>
<string name="show_ime" msgid="2506087537466597099">"Paturēt ekrānā, kamēr ir aktīva fiziskā tastatūra"</string>
<string name="hardware" msgid="194658061510127999">"Virtuālās tastatūras rādīšana"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Fiziskās tastatūras konfigurēšana"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Pieskarieties, lai atlasītu valodu un izkārtojumu"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidāti"</u></string>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index 71c1951..060a9fa 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Содржините се скриени поради политиката"</string>
<string name="safeMode" msgid="2788228061547930246">"Безбеден режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Систем Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Префрлете на личен профил"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Префрли на работен профил"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакти"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"пристапува до контактите"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Локација"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"СПОДЕЛИ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ОДБИЈ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Измени тастатура"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Други тастатури"</string>
<string name="show_ime" msgid="2506087537466597099">"Прикажувај го на екранот додека е активна физичката тастатура"</string>
<string name="hardware" msgid="194658061510127999">"Прикажи виртуелна тастатура"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Конфигурирајте физичка тастатура"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Допрете за избирање јазик и распоред"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index 92f9282..f6ff1d8 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"നയം അനുസരിച്ച് ഉള്ളടക്കം മറച്ചിരിക്കുന്നു"</string>
<string name="safeMode" msgid="2788228061547930246">"സുരക്ഷിത മോഡ്"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android സിസ്റ്റം"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"വ്യക്തിഗത പ്രൊഫൈലിലേക്ക് മാറുക"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"ഔദ്യോഗിക പ്രൊഫൈലിലേക്ക് മാറുക"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"കോൺടാക്റ്റുകൾ"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"നിങ്ങളുടെ കോൺടാക്റ്റുകൾ ആക്സസ്സ് ചെയ്യുക"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"ലൊക്കേഷൻ"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"പങ്കിടുക"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"നിരസിക്കുക"</string>
<string name="select_input_method" msgid="8547250819326693584">"കീബോഡ് മാറ്റുക"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"മറ്റ് കീബോർഡുകൾ"</string>
<string name="show_ime" msgid="2506087537466597099">"ഫിസിക്കൽ കീബോർഡ് സജീവമായിരിക്കുമ്പോൾ സ്ക്രീനിൽ നിലനിർത്തുക"</string>
<string name="hardware" msgid="194658061510127999">"വെർച്വൽ കീബോർഡ് കാണിക്കുക"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"ഫിസിക്കൽ കീബോർഡ് കോൺഫിഗർ ചെയ്യുക"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ഭാഷയും ലേഔട്ടും തിരഞ്ഞെടുക്കുന്നതിന് ടാപ്പുചെയ്യുക"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"കാൻഡിഡേറ്റുകൾ"</u></string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index c1cba4f..75105e6 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Удирдамжийн дагуу нуусан агуулга"</string>
<string name="safeMode" msgid="2788228061547930246">"Аюулгүй горим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Андройд систем"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"\"Хувийн\" руу шилжих"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"\"Ажлын\" руу шилжих"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Харилцагчдын хаяг"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"харилцагч руугаа хандах"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Байршил"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ХУВААЛЦАХ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ТАТГАЛЗАХ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Гарыг өөрчлөх"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Бусад гар"</string>
<string name="show_ime" msgid="2506087537466597099">"Бодит гар идэвхтэй үед үүнийг дэлгэцэнд харуулна уу"</string>
<string name="hardware" msgid="194658061510127999">"Хийсвэр гарыг харуулах"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Биет гарыг хэлбэрт оруулах"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Хэл болон бүдүүвчийг сонгохын тулд дарна уу"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"нэр дэвшигч"</u></string>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index f41e6ed..8a3e564 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"धोरणाद्वारे सामग्री लपविली"</string>
<string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android सिस्टम"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"वैयक्तिकवर स्विच करा"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"कार्यावर स्विच करा"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"संपर्क"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"आपल्या संपर्कांवर प्रवेश"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"स्थान"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"सामायिक करा"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"नकार द्या"</string>
<string name="select_input_method" msgid="8547250819326693584">"कीबोर्ड बदला"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"इतर कीबोर्ड"</string>
<string name="show_ime" msgid="2506087537466597099">"भौतिक कीबोर्ड सक्रिय असताना त्यास स्क्रीनवर ठेवा"</string>
<string name="hardware" msgid="194658061510127999">"व्हर्च्युअल कीबोर्ड दर्शवा"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"वास्तविक कीबोर्ड कॉन्फिगर करा"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा आणि लेआउट निवडण्यासाठी टॅप करा"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"उमेदवार"</u></string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 9a69bf9..5db9c77 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Kandungan disembunyikan oleh dasar"</string>
<string name="safeMode" msgid="2788228061547930246">"Mod selamat"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Beralih kepada Peribadi"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Beralih kepada Kerja"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kenalan"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"mengakses kenalan anda"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokasi"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"KONGSI"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"TOLAK"</string>
<string name="select_input_method" msgid="8547250819326693584">"Tukar papan kekunci"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Papan kekunci lain"</string>
<string name="show_ime" msgid="2506087537466597099">"Pastikannya pada skrin, semasa papan kekunci fizikal aktif"</string>
<string name="hardware" msgid="194658061510127999">"Tunjukkan papan kekunci maya"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurasikan papan kekunci fizikal"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ketik untuk memilih bahasa dan susun atur"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index b3c80d5..5e5ec4e 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"မူဝါဒမှ အကြောင်းအရာများကို ဝှက်ထားသည်"</string>
<string name="safeMode" msgid="2788228061547930246">"အန္တရာယ်ကင်းမှု စနစ်(Safe mode)"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android စနစ်"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"ကိုယ်ပိုင်သီးသန့်အဖြစ် ပြောင်းပါ"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"အလုပ်သို့ ပြောင်းပါ"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"အဆက်အသွယ်များ"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"သင့် အဆက်အသွယ်များအား ဝင်ရောက်သုံးရန်"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"တည်နေရာ"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"မျှဝေပါ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ငြင်းပယ်ပါ"</string>
<string name="select_input_method" msgid="8547250819326693584">"ကီးဘုတ် ပြောင်းလဲရန်"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"အခြားကီးဘုတ်များ"</string>
<string name="show_ime" msgid="2506087537466597099">"စက်၏ကီးဘုတ်ကိုအသုံးပြုနေစဉ် ၎င်းကိုမျက်နှာပြင်ပေါ်တွင် ထားပါ"</string>
<string name="hardware" msgid="194658061510127999">"ကီးဘုတ်အတုပြရန်"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"ရုပ်ပိုင်းဆိုင်ရာ အသွင်အပြင်ကို ပြင်ဆင်သတ်မှတ်ပါ"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ဘာသာစကားနှင့် အသွင်အပြင်ရွေးချယ်ရန် တို့ပါ"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"ရွေးချယ်ခံမည့်သူ"</u></string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index bebf593..cfccdeb 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Innholdet er skjult i henhold til retningslinjene"</string>
<string name="safeMode" msgid="2788228061547930246">"Sikkermodus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Bytt til den personlige profilen"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Bytt til jobbprofilen"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakter"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"se kontaktene dine"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Posisjon"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"DEL"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"AVSLÅ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Endre tastatur"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Andre tastaturoppsett"</string>
<string name="show_ime" msgid="2506087537466597099">"Ha den på skjermen mens det fysiske tastaturet er aktivt"</string>
<string name="hardware" msgid="194658061510127999">"Vis det virtuelle tastaturet"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurer et fysisk tastatur"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Trykk for å velge språk og layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
<string name="candidates_style" msgid="4333913089637062257">"TAG_FONT"<u>"kandidater"</u>"CLOSE_FONT"</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 24bb1f0..fb817b5 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"नीतिद्वारा लुकाइएका सामग्री"</string>
<string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
<string name="android_system_label" msgid="6577375335728551336">"एन्ड्रोइड प्रणाली"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"व्यक्तिगत प्रोफाइलमा स्विच गर्नुहोस्"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"कार्य प्रोफाइलमा स्विच गर्नुहोस्"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"सम्पर्कहरू"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"तपाईँको सम्पर्कमा पहुँच गर्नुहोस्"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"स्थान"</string>
@@ -1069,13 +1067,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"साझेदारी गर्नुहोस्"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"अस्वीकार गर्नुहोस्"</string>
<string name="select_input_method" msgid="8547250819326693584">"कुञ्जीपाटी परिवर्तन गर्नुहोस्"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"अन्य किबोर्डहरू"</string>
<string name="show_ime" msgid="2506087537466597099">"भौतिक किबोर्ड सक्रिय हुँदा यसलाई स्क्रिनमा राख्नुहोस्"</string>
<string name="hardware" msgid="194658061510127999">"भर्चुअल किबोर्ड देखाउनुहोस्"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"फिजिकल किबोर्डलाई कन्फिगर गर्नुहोस्"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा र लेआउट चयन गर्न ट्याप गर्नुहोस्"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"उम्मेदवार"</u></string>
diff --git a/core/res/res/values-night/themes_material_daynight.xml b/core/res/res/values-night/themes_material_daynight.xml
deleted file mode 100644
index b344582..0000000
--- a/core/res/res/values-night/themes_material_daynight.xml
+++ /dev/null
@@ -1,117 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 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.
--->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see themes_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-<resources>
-
- <!-- Material theme (day/night version) for activities. -->
- <style name="Theme.Material.DayNight" parent="Theme.Material" />
-
- <!-- Variant of Material.DayNight that has a solid (opaque) action bar
- with an inverse color profile. The dark action bar sharply stands out against
- the light content (when applicable). -->
- <style name="Theme.Material.DayNight.DarkActionBar" parent="Theme.Material" />
-
- <!-- Variant of Material.DayNight with no action bar. -->
- <style name="Theme.Material.DayNight.NoActionBar" parent="Theme.Material.NoActionBar" />
-
- <!-- Variant of Material.DayNight that has no title bar and fills
- the entire screen. This theme
- sets {@link android.R.attr#windowFullscreen} to true. -->
- <style name="Theme.Material.DayNight.NoActionBar.Fullscreen" parent="Theme.Material.NoActionBar.Fullscreen" />
-
- <!-- Variant of Material.DayNight that has no title bar and fills
- the entire screen and extends into the display overscan region. This theme
- sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
- to true. -->
- <style name="Theme.Material.DayNight.NoActionBar.Overscan" parent="Theme.Material.NoActionBar.Overscan" />
-
- <!-- Variant of Material.DayNight that has no title bar and translucent
- system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
- {@link android.R.attr#windowTranslucentNavigation} to true. -->
- <style name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" parent="Theme.Material.NoActionBar.TranslucentDecor" />
-
- <!-- Default Material.DayNight theme for panel windows. This removes all extraneous
- window decorations, so you basically have an empty rectangle in which
- to place your content. It makes the window floating, with a transparent
- background, and turns off dimming behind the window. -->
- <style name="Theme.Material.DayNight.Panel" parent="Theme.Material.Panel" />
-
- <!-- Material theme (day/night version) for dialog windows and activities,
- which is used by the {@link android.app.Dialog} class. This changes
- the window to be floating (not fill the entire screen), and puts a
- frame around its contents. You can set this theme on an activity if
- you would like to make an activity that looks like a Dialog. -->
- <style name="Theme.Material.DayNight.Dialog" parent="Theme.Material.DayNight.BaseDialog" />
- <style name="Theme.Material.DayNight.BaseDialog" parent="Theme.Material.BaseDialog" />
-
- <!-- Variant of Theme.Material.DayNight.Dialog that has a nice minimum width for
- a regular dialog. -->
- <style name="Theme.Material.DayNight.Dialog.MinWidth" parent="Theme.Material.Dialog.MinWidth" />
-
- <!-- Variant of Theme.Material.DayNight.Dialog that does not include a title bar. -->
- <style name="Theme.Material.DayNight.Dialog.NoActionBar" parent="Theme.Material.Dialog.NoActionBar" />
-
- <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a nice minimum width for
- a regular dialog. -->
- <style name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Dialog.NoActionBar.MinWidth" />
-
- <!-- Variant of Theme.Material.DayNight.Dialog that has a fixed size. -->
- <style name="Theme.Material.DayNight.Dialog.FixedSize" parent="Theme.Material.Dialog.FixedSize" />
-
- <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a fixed size. -->
- <style name="Theme.Material.DayNight.Dialog.NoActionBar.FixedSize" parent="Theme.Material.Dialog.NoActionBar.FixedSize" />
-
- <!-- Theme for a window that will be displayed either full-screen on
- smaller screens (small, normal) or as a dialog on larger screens
- (large, xlarge). -->
- <style name="Theme.Material.DayNight.DialogWhenLarge" parent="Theme.Material.DialogWhenLarge" />
-
- <!-- Theme for a window with a dark action bar that will be displayed
- either full-screen on smaller screens (small, normal) or as a dialog
- on larger screens (large, xlarge). -->
- <style name="Theme.Material.DayNight.DialogWhenLarge.DarkActionBar" parent="Theme.Material.DialogWhenLarge" />
-
- <!-- Theme for a window without an action bar that will be displayed either full-screen
- on smaller screens (small, normal) or as a dialog on larger screens
- (large, xlarge). -->
- <style name="Theme.Material.DayNight.DialogWhenLarge.NoActionBar" parent="Theme.Material.DialogWhenLarge.NoActionBar" />
-
- <!-- Theme for a presentation window on a secondary display. -->
- <style name="Theme.Material.DayNight.Dialog.Presentation" parent="Theme.Material.Dialog.Presentation" />
-
- <!-- Material user theme for alert dialog windows, which is used by the
- {@link android.app.AlertDialog} class. -->
- <style name="Theme.Material.DayNight.Dialog.Alert" parent="Theme.Material.DayNight.Dialog.BaseAlert" />
- <style name="Theme.Material.DayNight.Dialog.BaseAlert" parent="Theme.Material.Dialog.BaseAlert" />
-
- <style name="Theme.Material.DayNight.SearchBar" parent="Theme.Material.SearchBar" />
- <style name="Theme.Material.DayNight.CompactMenu" parent="Theme.Material.CompactMenu" />
-
-</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 5759cad..3de8496 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Content verborgen op basis van beleid"</string>
<string name="safeMode" msgid="2788228061547930246">"Veilige modus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-systeem"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Overschakelen naar persoonlijk profiel"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Overschakelen naar werkprofiel"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacten"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"toegang krijgen tot je contacten"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Locatie"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"DELEN"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"WEIGEREN"</string>
<string name="select_input_method" msgid="8547250819326693584">"Toetsenbord wijzigen"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Andere toetsenborden"</string>
<string name="show_ime" msgid="2506087537466597099">"Dit op het scherm weergeven terwijl het fysieke toetsenbord actief is"</string>
<string name="hardware" msgid="194658061510127999">"Virtueel toetsenbord tonen"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Fysiek toetsenbord configureren"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tik om een taal en indeling te selecteren"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidaten"</u></string>
diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
index b984760..87f973f 100644
--- a/core/res/res/values-pa-rIN/strings.xml
+++ b/core/res/res/values-pa-rIN/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ਨੀਤੀ ਦੁਆਰਾ ਸਮੱਗਰੀ ਲੁਕਾਈ ਗਈ"</string>
<string name="safeMode" msgid="2788228061547930246">"ਸੁਰੱਖਿਅਤ ਮੋਡ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"ਨਿੱਜੀ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"ਕੰਮ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"ਸੰਪਰਕ"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"ਆਪਣੇ ਸੰਪਰਕਾਂ ਨੂੰ ਐਕਸੈਸ ਕਰੋ"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"ਨਿਰਧਾਰਿਤ ਸਥਾਨ"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ਸਾਂਝੀ ਕਰੋ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ਅਸਵੀਕਾਰ ਕਰੋ"</string>
<string name="select_input_method" msgid="8547250819326693584">"ਕੀਬੋਰਡ ਬਦਲੋ"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"ਹੋਰ ਕੀ-ਬੋਰਡ"</string>
<string name="show_ime" msgid="2506087537466597099">"ਭੌਤਿਕ ਕੀ-ਬੋਰਡ ਸਰਗਰਮ ਹੋਣ ਦੌਰਾਨ ਇਸ ਨੂੰ ਸਕ੍ਰੀਨ \'ਤੇ ਬਣਾਈ ਰੱਖੋ"</string>
<string name="hardware" msgid="194658061510127999">"ਵਰਚੁਅਲ ਕੀ-ਬੋਰਡ ਵਿਖਾਓ"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"ਭੌਤਿਕ ਕੀ-ਬੋਰਡ ਦਾ ਸੰਰੂਪਣ ਕਰੋ"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ਭਾਸ਼ਾ ਅਤੇ ਖਾਕਾ ਚੁਣਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"ਉਮੀਦਵਾਰ"</u></string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 7248f4a..6be9a9d 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -237,10 +237,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Treść ukryta z powodu zasad"</string>
<string name="safeMode" msgid="2788228061547930246">"Tryb awaryjny"</string>
<string name="android_system_label" msgid="6577375335728551336">"System Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Włącz profil osobisty"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Włącz profil do pracy"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakty"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"dostęp do kontaktów"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokalizacja"</string>
@@ -1079,13 +1077,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"UDOSTĘPNIJ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODRZUĆ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Zmień klawiaturę"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Inne klawiatury"</string>
<string name="show_ime" msgid="2506087537466597099">"Pozostaw na ekranie, gdy aktywna jest klawiatura fizyczna"</string>
<string name="hardware" msgid="194658061510127999">"Pokaż klawiaturę wirtualną"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Skonfiguruj klawiaturę fizyczną"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Kliknij, by wybrać język i układ"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCĆDEĘFGHIJKLŁMNŃOÓPQRSŚTUVWXYZŹŻ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandydaci"</u></string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index bddb0fc..c8004bf 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Conteúdo ocultado pela política"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Alternar para \"Pessoal\""</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Alternar para \"Trabalho\""</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contatos"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"acesse seus contatos"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Local"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTILHAR"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RECUSAR"</string>
<string name="select_input_method" msgid="8547250819326693584">"Alterar teclado"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Outros teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Manter na tela enquanto o teclado físico estiver ativo"</string>
<string name="hardware" msgid="194658061510127999">"Mostrar teclado virtual"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configurar teclado físico"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 68c4bd9..c2ba8ad 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Conteúdo ocultado pela política"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Mudar para pessoal"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Mudar para trabalho"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactos"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"aceder aos contactos"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Localização"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"PARTILHAR"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RECUSAR"</string>
<string name="select_input_method" msgid="8547250819326693584">"Alterar teclado"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Outros teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Manter no ecrã enquanto o teclado físico estiver ativo"</string>
<string name="hardware" msgid="194658061510127999">"Mostrar o teclado virtual"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configurar teclado físico"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o esquema"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index bddb0fc..c8004bf 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Conteúdo ocultado pela política"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Alternar para \"Pessoal\""</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Alternar para \"Trabalho\""</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contatos"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"acesse seus contatos"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Local"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTILHAR"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RECUSAR"</string>
<string name="select_input_method" msgid="8547250819326693584">"Alterar teclado"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Outros teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Manter na tela enquanto o teclado físico estiver ativo"</string>
<string name="hardware" msgid="194658061510127999">"Mostrar teclado virtual"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configurar teclado físico"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 58c9383..7485e65 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -235,10 +235,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Conținutul este ascuns conform politicii"</string>
<string name="safeMode" msgid="2788228061547930246">"Mod sigur"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistemul Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Comutați la Personal"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Comutați la Serviciu"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Persoane de contact"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"acceseze persoanele de contact"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Locație"</string>
@@ -1071,13 +1069,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"TRIMITEȚI"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REFUZAȚI"</string>
<string name="select_input_method" msgid="8547250819326693584">"Schimbați tastatura"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Alte tastaturi"</string>
<string name="show_ime" msgid="2506087537466597099">"Se păstrează pe ecran cât timp este activată tastatura fizică"</string>
<string name="hardware" msgid="194658061510127999">"Afișați tastatura virtuală"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configurați tastatura fizică"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Atingeți pentru a selecta limba și aspectul"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidați"</u></string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 345bb49..5926bfd 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -237,10 +237,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Содержимое скрыто в соответствии с заданными правилами"</string>
<string name="safeMode" msgid="2788228061547930246">"Безопасный режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Перейти в личный профиль"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Перейти в рабочий профиль"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакты"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"доступ к контактам"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Местоположение"</string>
@@ -1079,13 +1077,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ПРЕДОСТАВИТЬ ДОСТУП"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ОТКЛОНИТЬ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Выбор раскладки"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Другие клавиатуры"</string>
<string name="show_ime" msgid="2506087537466597099">"Показывать на экране, когда физическая клавиатура включена"</string>
<string name="hardware" msgid="194658061510127999">"Виртуальная клавиатура"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Настройка физической клавиатуры"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Нажмите, чтобы выбрать язык и раскладку"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"варианты"</u></string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index f01ab61..6c76da0 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ප්රතිපත්තිය විසින් අන්තර්ගතය සඟවන ලදී"</string>
<string name="safeMode" msgid="2788228061547930246">"ආරක්ෂිත ආකාරය"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android පද්ධතිය"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"පුද්ගලික වෙත මාරු වන්න"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"කාර්යාලය වෙත මාරු වන්න"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"සම්බන්ධතා"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"ඔබේ සම්බන්ධතාවලට පිවිසෙන්න"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"ස්ථානය"</string>
@@ -1065,13 +1063,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"බෙදා ගන්න"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ප්රතික්ෂේප කරන්න"</string>
<string name="select_input_method" msgid="8547250819326693584">"යතුරු පුවරු වෙනස් කිරීම"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"වෙනත් යතුරු පුවරු"</string>
<string name="show_ime" msgid="2506087537466597099">"භෞතික යතුරු පුවරුව සක්රිය අතරතුර එය තිරය මත තබා ගන්න"</string>
<string name="hardware" msgid="194658061510127999">"අතථ්ය යතුරු පුවරුව පෙන්වන්න"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"භෞතික යතුරු පුවරුව වින්යාස කරන්න"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"භාෂාව හා පිරිසැලසුම තේරීමට තට්ටු කරන්න"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"අපේක්ෂකයන්"</u></string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 1a3ef4c..ec45070 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -237,10 +237,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Obsah je na základe pravidiel skrytý"</string>
<string name="safeMode" msgid="2788228061547930246">"Núdzový režim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Prepnúť na osobný"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Prepnúť na pracovný"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakty"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"prístup k vašim kontaktom"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Poloha"</string>
@@ -1079,13 +1077,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ZDIEĽAŤ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODMIETNUŤ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Zmeniť klávesnicu"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Ďalšie klávesnice"</string>
<string name="show_ime" msgid="2506087537466597099">"Ponechať na obrazovke, keď je aktívna fyzická klávesnica"</string>
<string name="hardware" msgid="194658061510127999">"Zobraziť virtuálnu klávesnicu"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurácia fyzickej klávesnice"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Klepnutím vyberte jazyk a rozloženie"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁÄBCČDĎDZDŽEÉFGHCHIÍJKLĽMNŇOÓÔPRŔSŠTŤUÚVWXYÝZŽ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index c102abb..b2dba7e0 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -237,10 +237,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Pravilnik je skril vsebino"</string>
<string name="safeMode" msgid="2788228061547930246">"Varni način"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Preklop na osebni profil"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Preklop na delovni profil"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Stiki"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"dostop do stikov"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokacija"</string>
@@ -1079,13 +1077,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"SKUPNA RABA"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"NE SPREJMEM"</string>
<string name="select_input_method" msgid="8547250819326693584">"Sprememba tipkovnice"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Druge tipkovnice"</string>
<string name="show_ime" msgid="2506087537466597099">"Ohrani na zaslonu, dokler je aktivna fizična tipkovnica"</string>
<string name="hardware" msgid="194658061510127999">"Pokaži navidezno tipkovnico"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfiguriranje fizične tipkovnice"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dotaknite se, če želite izbrati jezik in postavitev."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index 9151893..1846399 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Përmbajtja është e fshehur për shkak të politikës"</string>
<string name="safeMode" msgid="2788228061547930246">"Modaliteti i sigurisë"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistemi \"android\""</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Ndryshoje te \"Personale\""</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Ndryshoje te \"Puna\""</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktet"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"qasu te kontaktet e tua"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Vendndodhja"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"SHPËRNDA"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REFUZO"</string>
<string name="select_input_method" msgid="8547250819326693584">"Ndërro tastierë"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Tastierat e tjera"</string>
<string name="show_ime" msgid="2506087537466597099">"Mbaje në ekran ndërsa tastiera fizike është aktive"</string>
<string name="hardware" msgid="194658061510127999">"Shfaq tastierën virtuale"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfiguro tastierën fizike"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Trokit për të zgjedhur gjuhën dhe strukturën"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidatë"</u></string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 9f8c2c0..2112dbb 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -235,10 +235,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Садржај је сакривен смерницама"</string>
<string name="safeMode" msgid="2788228061547930246">"Безбедни режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android систем"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Пређи на Лични профил"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Пређи на профил за Work"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакти"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"приступи контактима"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Локација"</string>
@@ -1071,13 +1069,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ДЕЛИ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ОДБИЈ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Промените тастатуру"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Друге тастатуре"</string>
<string name="show_ime" msgid="2506087537466597099">"Задржи га на екрану док је физичка тастатура активна"</string>
<string name="hardware" msgid="194658061510127999">"Прикажи виртуелну тастатуру"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Конфигуришите физичку тастатуру"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Додирните да бисте изабрали језик и распоред"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index d3855f8..832d4a2 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Innehåll har dolts p.g.a. en policy"</string>
<string name="safeMode" msgid="2788228061547930246">"Säkert läge"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Byt till din personliga profil"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Byt till jobbprofilen"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakter"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"få tillgång till dina kontakter"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Plats"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"DELA"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"AVVISA"</string>
<string name="select_input_method" msgid="8547250819326693584">"Byt tangentbord"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Andra tangentbord"</string>
<string name="show_ime" msgid="2506087537466597099">"Ha kvar den på skärmen när det fysiska tangentbordet används"</string>
<string name="hardware" msgid="194658061510127999">"Visa virtuellt tangentbord"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurera fysiskt tangentbord"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tryck om du vill välja språk och layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index fd5c2c7..e0a32f6 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -235,10 +235,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Maudhui yamefichwa kulingana na sera"</string>
<string name="safeMode" msgid="2788228061547930246">"Mtindo salama"</string>
<string name="android_system_label" msgid="6577375335728551336">"Mfumo wa Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Badili uweke wasifu wa Binafsi"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Badili uweke wasifu wa Kazini"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Anwani"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"ifikie anwani zako"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Mahali"</string>
@@ -1065,13 +1063,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"SHIRIKI"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"KATAA"</string>
<string name="select_input_method" msgid="8547250819326693584">"Badilisha kibodi"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Kibodi zingine"</string>
<string name="show_ime" msgid="2506087537466597099">"Iweke kwenye skrini wakati kibodi inapotumika"</string>
<string name="hardware" msgid="194658061510127999">"Onyesha kibodi pepe"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Sanidi kibodi halisi"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Gonga ili uchague lugha na muundo"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"wagombeaji"</u></string>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index f92177a..773301f 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"கொள்கையின்படி உள்ளடக்கம் மறைக்கப்பட்டது"</string>
<string name="safeMode" msgid="2788228061547930246">"பாதுகாப்பு பயன்முறை"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android அமைப்பு"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"தனிப்பட்ட சுயவிவரத்திற்கு மாறு"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"பணிச் சுயவிவரத்திற்கு மாறு"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"தொடர்புகள்"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"தொடர்புகளை அணுகும்"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"இருப்பிடம்"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"பகிர்"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"வேண்டாம்"</string>
<string name="select_input_method" msgid="8547250819326693584">"விசைப்பலகையை மாற்று"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"பிற விசைப்பலகைகள்"</string>
<string name="show_ime" msgid="2506087537466597099">"கைமுறை விசைப்பலகை இயக்கத்தில் இருக்கும் போது IMEஐ திரையில் வைத்திரு"</string>
<string name="hardware" msgid="194658061510127999">"விர்ச்சுவல் விசைப்பலகையை காட்டு"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"கைமுறை விசைப்பலகையை உள்ளமைக்கவும்"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"மொழியையும் தளவமைப்பையும் தேர்ந்தெடுக்க, தட்டவும்"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"கேன்டிடேட்ஸ்"</u></string>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 9b5fc01..4809c98 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"విధానం ద్వారా కంటెంట్లు దాచబడ్డాయి"</string>
<string name="safeMode" msgid="2788228061547930246">"సురక్షిత మోడ్"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android సిస్టమ్"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"వ్యక్తిగతానికి మార్చు"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"కార్యాలయానికి మార్చు"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"పరిచయాలు"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"మీ పరిచయాలను ప్రాప్యత చేయడానికి"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"స్థానం"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"భాగస్వామ్యం చేయి"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"తిరస్కరిస్తున్నాను"</string>
<string name="select_input_method" msgid="8547250819326693584">"కీబోర్డ్ను మార్చు"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"ఇతర కీబోర్డ్లు"</string>
<string name="show_ime" msgid="2506087537466597099">"దీన్ని భౌతిక కీబోర్డ్ సక్రియంగా ఉన్నప్పుడు స్క్రీన్పై ఉంచుతుంది"</string>
<string name="hardware" msgid="194658061510127999">"వర్చువల్ కీబోర్డ్ను చూపు"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"భౌతిక కీబోర్డుని కాన్ఫిగర్ చేయండి"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"భాష మరియు లేఅవుట్ను ఎంచుకోవడానికి నొక్కండి"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"క్యాండిడేట్లు"</u></string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index ca401bc..0ea2e52 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"มีการซ่อนเนื้อหาโดยนโยบาย"</string>
<string name="safeMode" msgid="2788228061547930246">"โหมดปลอดภัย"</string>
<string name="android_system_label" msgid="6577375335728551336">"ระบบ Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"เปลี่ยนไปใช้โปรไฟล์ส่วนตัว"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"เปลี่ยนไปใช้โปรไฟล์งาน"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"รายชื่อติดต่อ"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"เข้าถึงรายชื่อติดต่อ"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"ตำแหน่ง"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"แชร์"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ปฏิเสธ"</string>
<string name="select_input_method" msgid="8547250819326693584">"เปลี่ยนแป้นพิมพ์"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"แป้นพิมพ์อื่นๆ"</string>
<string name="show_ime" msgid="2506087537466597099">"เปิดทิ้งไว้บนหน้าจอในระหว่างใช้งานแป้นพิมพ์จริง"</string>
<string name="hardware" msgid="194658061510127999">"แสดงแป้นพิมพ์เสมือน"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"กำหนดค่าแป้นพิมพ์จริง"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"แตะเพื่อเลือกภาษาและรูปแบบ"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"ตัวเลือก"</u></string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 1a63a99..00918a4 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Itinago ang mga content alinsunod sa patakaran"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Lumipat sa Personal"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Lumipat sa para sa Trabaho"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Mga Contact"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"ina-access ang iyong mga contact"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokasyon"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"IBAHAGI"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"TANGGIHAN"</string>
<string name="select_input_method" msgid="8547250819326693584">"Baguhin ang keyboard"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Iba pang mga keyboard"</string>
<string name="show_ime" msgid="2506087537466597099">"Panatilihin ito sa screen habang aktibo ang pisikal na keyboard"</string>
<string name="hardware" msgid="194658061510127999">"Ipakita ang virtual keyboard"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"I-configure ang pisikal na keyboard"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"I-tap upang pumili ng wika at layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"mga kandidato"</u></string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index e4a44d2..4db8264 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"İçerikler politika nedeniyle gizlendi"</string>
<string name="safeMode" msgid="2788228061547930246">"Güvenli mod"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android Sistemi"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Kişisel Profile Geç"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"İş Profiline Geç"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kişiler"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"kişilerinize erişme"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Konum"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"PAYLAŞ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REDDET"</string>
<string name="select_input_method" msgid="8547250819326693584">"Klavyeyi değiştir"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Diğer klavyeler"</string>
<string name="show_ime" msgid="2506087537466597099">"Fiziksel klavye etkin durumdayken ekranda tut"</string>
<string name="hardware" msgid="194658061510127999">"Sanal klavyeyi göster"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Fiziksel klavyeyi yapılandırın"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dili ve düzeni seçmek için hafifçe dokunun"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"adaylar"</u></string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index a6020e8..fe7be12 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -237,10 +237,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Вміст сховано згідно з правилом"</string>
<string name="safeMode" msgid="2788228061547930246">"Безп. режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Перейти в особистий профіль"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Перейти в робочий профіль"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакти"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"отримувати доступ до контактів"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Геодані"</string>
@@ -1079,13 +1077,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ПОДІЛИТИСЯ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ВІДХИЛИТИ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Змінити клавіатуру"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Інші клавіатури"</string>
<string name="show_ime" msgid="2506087537466597099">"Утримуйте на екрані, коли активна фізична клавіатура"</string>
<string name="hardware" msgid="194658061510127999">"Показати віртуальну клавіатуру"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Налаштуйте фізичну клавіатуру"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Торкніться, щоб вибрати мову та розкладку"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index b515c55..5236b7f 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"مواد پالیسی کے تحت مخفی ہے"</string>
<string name="safeMode" msgid="2788228061547930246">"حفاظتی وضع"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android سسٹم"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"ذاتی پر سوئچ کریں"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"کام پر سوئچ کریں"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"رابطے"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"اپنے رابطوں تک رسائی حاصل کریں"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"مقام"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"اشتراک کریں"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"مسترد کریں"</string>
<string name="select_input_method" msgid="8547250819326693584">"کی بورڈ تبدیل کریں"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"دیگر کی بورڈز"</string>
<string name="show_ime" msgid="2506087537466597099">"جب فزیکل کی بورڈ فعال ہو تو IME کو اسکرین پر رکھیں"</string>
<string name="hardware" msgid="194658061510127999">"ورچوئل کی بورڈ دکھائیں"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"فزیکل کی بورڈ کنفیگر کریں"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"زبان اور لے آؤٹ منتخب کرنے کیلئے تھپتھپائیں"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"امیدواران"</u></string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index 6323f52..6cb65a3 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Qoidaga muvofiq kontent yashirilgan"</string>
<string name="safeMode" msgid="2788228061547930246">"Xavfsiz usul"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android tizimi"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Shaxsiy profilga o‘tish"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Ishchi profilga o‘tish"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktlar"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"kontaktlarga kirish"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Joylashuv"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ULASHISH"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RAD ETISH"</string>
<string name="select_input_method" msgid="8547250819326693584">"Klaviaturani o‘zgartirish"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Boshqa klaviaturalar"</string>
<string name="show_ime" msgid="2506087537466597099">"Tashqi klaviaturadan foydalanilayotganda buni ekranda saqlab turish"</string>
<string name="hardware" msgid="194658061510127999">"Virtual klaviatura ko‘rsatilsin"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Tashqi klaviaturani sozlash"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Til va sxemani belgilash uchun bosing"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"nomzodlar"</u></string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 10516af..29eef92 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Nội dung bị ẩn theo chính sách"</string>
<string name="safeMode" msgid="2788228061547930246">"Chế độ an toàn"</string>
<string name="android_system_label" msgid="6577375335728551336">"Hệ thống Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Chuyển sang Cá nhân"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Chuyển sang Công việc"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Danh bạ"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"truy cập vào danh bạ của bạn"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Vị trí"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"CHIA SẺ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"TỪ CHỐI"</string>
<string name="select_input_method" msgid="8547250819326693584">"Thay đổi bàn phím"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Bàn phím khác"</string>
<string name="show_ime" msgid="2506087537466597099">"Tiếp tục sử dụng ứng dụng trên màn hình trong khi bàn phím thực đang hoạt động"</string>
<string name="hardware" msgid="194658061510127999">"Hiển thị bàn phím ảo"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Định cấu hình bàn phím thực"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Nhấn để chọn ngôn ngữ và bố cục"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"ứng viên"</u></string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index f7bcaba..c216be8 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"内容已隐藏(根据政策规定)"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系统"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"切换为“个人”"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"切换为“工作”"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"通讯录"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"访问您的通讯录"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"位置信息"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"分享"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"拒绝"</string>
<string name="select_input_method" msgid="8547250819326693584">"更改键盘"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"其他键盘"</string>
<string name="show_ime" msgid="2506087537466597099">"连接到实体键盘时使其在屏幕上保持显示状态"</string>
<string name="hardware" msgid="194658061510127999">"显示虚拟键盘"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"配置实体键盘"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"点按即可选择语言和布局"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"候选"</u></string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 15e9a5e..28f2bac 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"已根據政策隱藏內容"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"切換至個人設定檔"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"切換至工作設定檔"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"通訊錄"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"存取您的通訊錄"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"位置"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"分享"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"拒絕"</string>
<string name="select_input_method" msgid="8547250819326693584">"變更鍵盤"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"其他鍵盤"</string>
<string name="show_ime" msgid="2506087537466597099">"在實體鍵盤處於連接狀態時保持顯示"</string>
<string name="hardware" msgid="194658061510127999">"顯示虛擬鍵盤"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"設定實體鍵盤"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"輕按即可選取語言和鍵盤配置"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"待選項目"</u></string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index a27f1b7..dfc7890 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"內容已依據政策隱藏"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"切換至個人設定檔"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"切換至公司設定檔"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"聯絡人"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"存取您的聯絡人"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"位置"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"分享"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"拒絕"</string>
<string name="select_input_method" msgid="8547250819326693584">"變更鍵盤"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"其他鍵盤"</string>
<string name="show_ime" msgid="2506087537466597099">"有連接的實體鍵盤時保持顯示"</string>
<string name="hardware" msgid="194658061510127999">"顯示虛擬鍵盤"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"設定實體鍵盤"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"輕觸即可選取語言和版面配置"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"待選項目"</u></string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 60be8fd..e32f26b 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -233,10 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Okuqukethwe kufihlwe inqubomgomo"</string>
<string name="safeMode" msgid="2788228061547930246">"Imodi ephephile"</string>
<string name="android_system_label" msgid="6577375335728551336">"Uhlelo lwe-Android"</string>
- <!-- no translation found for user_owner_label (1119010402169916617) -->
- <skip />
- <!-- no translation found for managed_profile_label (5289992269827577857) -->
- <skip />
+ <string name="user_owner_label" msgid="1119010402169916617">"Shintshela komuntu siqu"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Shintshela kumsebenzi"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Oxhumana nabo"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"finyelela koxhumana nabo"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Indawo"</string>
@@ -1063,13 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"YABELANA"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"YENQABA"</string>
<string name="select_input_method" msgid="8547250819326693584">"Shintsha ikhibhodi"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Amanye amakhibhodi"</string>
<string name="show_ime" msgid="2506087537466597099">"Yigcine kusikrini ngenkathi kusebenza ikhibhodi ephathekayo"</string>
<string name="hardware" msgid="194658061510127999">"Bonisa ikhibhodi ebonakalayo"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Lungisa ikhibhodi yoqobo"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Thepha ukuze ukhethe ulimi nesakhiwo"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"abahlanganyeli"</u></string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 4429001..0ed1f13 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3528,6 +3528,13 @@
This setting implies fastScrollEnabled. -->
<attr name="fastScrollAlwaysVisible" format="boolean" />
</declare-styleable>
+ <!-- @hide -->
+ <declare-styleable name="RecycleListView">
+ <!-- Bottom padding to use when no buttons are present. -->
+ <attr name="paddingBottomNoButtons" format="dimension" />
+ <!-- Top padding to use when no title is present. -->
+ <attr name="paddingTopNoTitle" format="dimension" />
+ </declare-styleable>
<declare-styleable name="AbsSpinner">
<!-- Reference to an array resource that will populate the Spinner. For static content,
this is simpler than populating the Spinner programmatically. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index d1c0895..5b4364d 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -225,6 +225,9 @@
granted any application pre-installed on the system image (not just privileged
apps). -->
<flag name="preinstalled" value="0x400" />
+ <!-- Additional flag from base permission type: this permission can be automatically
+ granted to the setup wizard app -->
+ <flag name="setup" value="0x800" />
</attr>
<!-- Flags indicating more context for a permission group. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 892b3d5..cae04ad 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -578,6 +578,9 @@
Software implementation will be used if config_hardware_auto_brightness_available is not set -->
<bool name="config_automatic_brightness_available">false</bool>
+ <!-- Fast brightness animation ramp rate -->
+ <integer translatable="false" name="config_brightness_ramp_rate_fast">200</integer>
+
<!-- Don't name config resources like this. It should look like config_annoyDianne -->
<bool name="config_annoy_dianne">true</bool>
@@ -2501,4 +2504,7 @@
<!-- True if the device requires AppWidgetService even if it does not have
the PackageManager.FEATURE_APP_WIDGETS feature -->
<bool name="config_enableAppWidgetService">false</bool>
+
+ <!-- True if the device supports Sustained Performance Mode-->
+ <bool name="config_sustainedPerformanceModeSupported">false</bool>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 71d9a1f..a21f276 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -450,6 +450,7 @@
<item type="dimen" format="integer" name="time_picker_column_end_material">1</item>
<item type="dimen" name="aerr_padding_list_top">15dp</item>
+ <item type="dimen" name="aerr_padding_list_bottom">8dp</item>
<item type="fraction" name="docked_stack_divider_fixed_ratio">34.15%</item>
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index ad2b335d..00e48a0 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -117,13 +117,13 @@
<dimen name="dialog_padding_material">24dp</dimen>
<dimen name="dialog_padding_top_material">18dp</dimen>
+ <dimen name="dialog_title_divider_material">8dp</dimen>
+ <dimen name="dialog_list_padding_top_no_title">8dp</dimen>
+ <dimen name="dialog_list_padding_bottom_no_buttons">8dp</dimen>
<!-- Dialog padding minus control padding, used to fix alignment. -->
<dimen name="select_dialog_padding_start_material">20dp</dimen>
- <!-- Padding above and below selection dialog lists. -->
- <dimen name="dialog_list_padding_vertical_material">8dp</dimen>
-
<dimen name="seekbar_track_background_height_material">2dp</dimen>
<dimen name="seekbar_track_progress_height_material">2dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 0839187..6ff7139 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2716,6 +2716,8 @@
<public type="style" name="Theme.Material.Light.DialogWhenLarge.DarkActionBar" />
<public type="style" name="Widget.Material.SeekBar.Discrete" />
+ <public type="style" name="Widget.Material.CompoundButton.Switch" />
+ <public type="style" name="Widget.Material.Light.CompoundButton.Switch" />
<public type="id" name="accessibilityActionSetProgress" />
<public type="id" name="icon_frame" />
diff --git a/core/res/res/values/styles_micro.xml b/core/res/res/values/styles_micro.xml
index 7dde5f8..341a0a4 100644
--- a/core/res/res/values/styles_micro.xml
+++ b/core/res/res/values/styles_micro.xml
@@ -17,27 +17,27 @@
<style name="Animation.Micro"/>
<style name="Animation.Micro.Activity" parent="Animation.Material.Activity">
- <item name="activityOpenEnterAnimation">@anim/slide_in_micro</item>
- <item name="activityOpenRemoteViewsEnterAnimation">@anim/slide_in_micro</item>
- <item name="activityOpenExitAnimation">@null</item>
+ <item name="activityOpenEnterAnimation">@anim/slide_in_enter_micro</item>
+ <item name="activityOpenRemoteViewsEnterAnimation">@anim/slide_in_enter_micro</item>
+ <item name="activityOpenExitAnimation">@anim/slide_in_exit_micro</item>
<item name="activityCloseEnterAnimation">@null</item>
<item name="activityCloseExitAnimation">@anim/slide_out_micro</item>
- <item name="taskOpenEnterAnimation">@anim/slide_in_micro</item>
- <item name="taskOpenExitAnimation">@null</item>
+ <item name="taskOpenEnterAnimation">@anim/slide_in_enter_micro</item>
+ <item name="taskOpenExitAnimation">@anim/slide_in_exit_micro</item>
<item name="taskCloseEnterAnimation">@null</item>
<item name="taskCloseExitAnimation">@anim/slide_out_micro</item>
- <item name="taskToFrontEnterAnimation">@anim/slide_in_micro</item>
- <item name="taskToFrontExitAnimation">@null</item>
+ <item name="taskToFrontEnterAnimation">@anim/slide_in_enter_micro</item>
+ <item name="taskToFrontExitAnimation">@anim/slide_in_exit_micro</item>
<item name="taskToBackEnterAnimation">@null</item>
<item name="taskToBackExitAnimation">@anim/slide_out_micro</item>
<item name="wallpaperOpenEnterAnimation">@null</item>
<item name="wallpaperOpenExitAnimation">@anim/slide_out_micro</item>
- <item name="wallpaperCloseEnterAnimation">@anim/slide_in_micro</item>
- <item name="wallpaperCloseExitAnimation">@null</item>
+ <item name="wallpaperCloseEnterAnimation">@anim/slide_in_enter_micro</item>
+ <item name="wallpaperCloseExitAnimation">@anim/slide_in_exit_micro</item>
<item name="wallpaperIntraOpenEnterAnimation">@null</item>
<item name="wallpaperIntraOpenExitAnimation">@anim/slide_out_micro</item>
- <item name="wallpaperIntraCloseEnterAnimation">@anim/slide_in_micro</item>
- <item name="wallpaperIntraCloseExitAnimation">@null</item>
+ <item name="wallpaperIntraCloseEnterAnimation">@anim/slide_in_enter_micro</item>
+ <item name="wallpaperIntraCloseExitAnimation">@anim/slide_in_exit_micro</item>
</style>
<style name="AlertDialog.Micro" parent="AlertDialog.Material.Light">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b0726d2..1e10f86 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1766,6 +1766,7 @@
<java-symbol type="integer" name="config_shutdownBatteryTemperature" />
<java-symbol type="integer" name="config_undockedHdmiRotation" />
<java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
+ <java-symbol type="integer" name="config_brightness_ramp_rate_fast" />
<java-symbol type="layout" name="am_compat_mode_dialog" />
<java-symbol type="layout" name="launch_warning" />
<java-symbol type="layout" name="safe_mode" />
@@ -2451,24 +2452,6 @@
<java-symbol type="id" name="aerr_close" />
<java-symbol type="id" name="aerr_mute" />
- <!-- Framework-private Material.DayNight styles. -->
- <java-symbol type="style" name="Theme.Material.DayNight" />
- <java-symbol type="style" name="Theme.Material.DayNight.DarkActionBar" />
- <java-symbol type="style" name="Theme.Material.DayNight.Dialog" />
- <java-symbol type="style" name="Theme.Material.DayNight.Dialog.Alert" />
- <java-symbol type="style" name="Theme.Material.DayNight.Dialog.MinWidth" />
- <java-symbol type="style" name="Theme.Material.DayNight.Dialog.NoActionBar" />
- <java-symbol type="style" name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" />
- <java-symbol type="style" name="Theme.Material.DayNight.Dialog.Presentation" />
- <java-symbol type="style" name="Theme.Material.DayNight.DialogWhenLarge" />
- <java-symbol type="style" name="Theme.Material.DayNight.DialogWhenLarge.NoActionBar" />
- <java-symbol type="style" name="Theme.Material.DayNight.NoActionBar" />
- <java-symbol type="style" name="Theme.Material.DayNight.NoActionBar.Fullscreen" />
- <java-symbol type="style" name="Theme.Material.DayNight.NoActionBar.Overscan" />
- <java-symbol type="style" name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" />
- <java-symbol type="style" name="Theme.Material.DayNight.Panel" />
- <java-symbol type="style" name="Theme.Material.DayNight.DialogWhenLarge.DarkActionBar" />
-
<java-symbol type="string" name="status_bar_rotate" />
<java-symbol type="string" name="status_bar_headset" />
<java-symbol type="string" name="status_bar_data_saver" />
@@ -2556,4 +2539,9 @@
<!-- WallpaperManager config -->
<java-symbol type="string" name="config_wallpaperCropperPackage" />
+
+ <java-symbol type="id" name="textSpacerNoTitle" />
+ <java-symbol type="id" name="titleDividerNoCustom" />
+
+ <java-symbol type="bool" name="config_sustainedPerformanceModeSupported" />
</resources>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index a361eda..6611eb1 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -1294,7 +1294,7 @@
</style>
<!-- Default theme for Settings and activities launched from Settings. -->
- <style name="Theme.Material.Settings" parent="Theme.Material.DayNight.DarkActionBar">
+ <style name="Theme.Material.Settings" parent="Theme.Material.Light.DarkActionBar">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
@@ -1304,7 +1304,7 @@
</style>
<!-- Default theme for Settings and activities launched from Settings. -->
- <style name="Theme.Material.Settings.NoActionBar" parent="Theme.Material.DayNight.NoActionBar">
+ <style name="Theme.Material.Settings.NoActionBar" parent="Theme.Material.Light.NoActionBar">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
@@ -1313,41 +1313,41 @@
<item name="panelMenuListTheme">@style/Theme.Material.Settings.CompactMenu</item>
</style>
- <style name="Theme.Material.Settings.BaseDialog" parent="Theme.Material.DayNight.BaseDialog">
+ <style name="Theme.Material.Settings.BaseDialog" parent="Theme.Material.Light.BaseDialog">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
</style>
<style name="Theme.Material.Settings.Dialog" parent="Theme.Material.Settings.BaseDialog" />
- <style name="Theme.Material.Settings.Dialog.BaseAlert" parent="Theme.Material.DayNight.Dialog.BaseAlert">
+ <style name="Theme.Material.Settings.Dialog.BaseAlert" parent="Theme.Material.Light.Dialog.BaseAlert">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
</style>
<style name="Theme.Material.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.BaseAlert" />
- <style name="Theme.Material.Settings.DialogWhenLarge" parent="Theme.Material.DayNight.DialogWhenLarge.DarkActionBar">
+ <style name="Theme.Material.Settings.DialogWhenLarge" parent="Theme.Material.Light.DialogWhenLarge.DarkActionBar">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
</style>
- <style name="Theme.Material.Settings.DialogWhenLarge.NoActionBar" parent="Theme.Material.DayNight.DialogWhenLarge.NoActionBar">
+ <style name="Theme.Material.Settings.DialogWhenLarge.NoActionBar" parent="Theme.Material.Light.DialogWhenLarge.NoActionBar">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
</style>
- <style name="Theme.Material.Settings.Dialog.Presentation" parent="Theme.Material.DayNight.Dialog.Presentation">
+ <style name="Theme.Material.Settings.Dialog.Presentation" parent="Theme.Material.Light.Dialog.Presentation">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
</style>
- <style name="Theme.Material.Settings.SearchBar" parent="Theme.Material.DayNight.SearchBar">
+ <style name="Theme.Material.Settings.SearchBar" parent="Theme.Material.Light.SearchBar">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
</style>
- <style name="Theme.Material.Settings.CompactMenu" parent="Theme.Material.DayNight.CompactMenu">
+ <style name="Theme.Material.Settings.CompactMenu" parent="Theme.Material.Light.CompactMenu">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
</style>
diff --git a/core/res/res/values/themes_material_daynight.xml b/core/res/res/values/themes_material_daynight.xml
deleted file mode 100644
index 4ecca6b..0000000
--- a/core/res/res/values/themes_material_daynight.xml
+++ /dev/null
@@ -1,117 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 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.
--->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see themes_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-<resources>
-
- <!-- Material theme (day/night vesion) for activities. -->
- <style name="Theme.Material.DayNight" parent="Theme.Material.Light" />
-
- <!-- Variant of Material.DayNight that has a solid (opaque) action bar
- with an inverse color profile. The dark action bar sharply stands out against
- the light content (when applicable). -->
- <style name="Theme.Material.DayNight.DarkActionBar" parent="Theme.Material.Light.DarkActionBar" />
-
- <!-- Variant of Material.DayNight with no action bar. -->
- <style name="Theme.Material.DayNight.NoActionBar" parent="Theme.Material.Light.NoActionBar" />
-
- <!-- Variant of Material.DayNight that has no title bar and fills
- the entire screen. This theme
- sets {@link android.R.attr#windowFullscreen} to true. -->
- <style name="Theme.Material.DayNight.NoActionBar.Fullscreen" parent="Theme.Material.Light.NoActionBar.Fullscreen" />
-
- <!-- Variant of Material.DayNight that has no title bar and fills
- the entire screen and extends into the display overscan region. This theme
- sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
- to true. -->
- <style name="Theme.Material.DayNight.NoActionBar.Overscan" parent="Theme.Material.Light.NoActionBar.Overscan" />
-
- <!-- Variant of Material.DayNight that has no title bar and translucent
- system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
- {@link android.R.attr#windowTranslucentNavigation} to true. -->
- <style name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" parent="Theme.Material.Light.NoActionBar.TranslucentDecor" />
-
- <!-- Default Material.DayNight theme for panel windows. This removes all extraneous
- window decorations, so you basically have an empty rectangle in which
- to place your content. It makes the window floating, with a transparent
- background, and turns off dimming behind the window. -->
- <style name="Theme.Material.DayNight.Panel" parent="Theme.Material.Light.Panel" />
-
- <!-- Material theme (day/night vesion) for dialog windows and activities,
- which is used by the {@link android.app.Dialog} class. This changes
- the window to be floating (not fill the entire screen), and puts a
- frame around its contents. You can set this theme on an activity if
- you would like to make an activity that looks like a Dialog. -->
- <style name="Theme.Material.DayNight.Dialog" parent="Theme.Material.DayNight.BaseDialog" />
- <style name="Theme.Material.DayNight.BaseDialog" parent="Theme.Material.Light.BaseDialog" />
-
- <!-- Variant of Theme.Material.DayNight.Dialog that has a nice minimum width for
- a regular dialog. -->
- <style name="Theme.Material.DayNight.Dialog.MinWidth" parent="Theme.Material.Light.Dialog.MinWidth" />
-
- <!-- Variant of Theme.Material.DayNight.Dialog that does not include a title bar. -->
- <style name="Theme.Material.DayNight.Dialog.NoActionBar" parent="Theme.Material.Light.Dialog.NoActionBar" />
-
- <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a nice minimum width for
- a regular dialog. -->
- <style name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Light.Dialog.NoActionBar.MinWidth" />
-
- <!-- Variant of Theme.Material.DayNight.Dialog that has a fixed size. -->
- <style name="Theme.Material.DayNight.Dialog.FixedSize" parent="Theme.Material.Light.Dialog.FixedSize" />
-
- <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a fixed size. -->
- <style name="Theme.Material.DayNight.Dialog.NoActionBar.FixedSize" parent="Theme.Material.Light.Dialog.NoActionBar.FixedSize" />
-
- <!-- Theme for a window that will be displayed either full-screen on
- smaller screens (small, normal) or as a dialog on larger screens
- (large, xlarge). -->
- <style name="Theme.Material.DayNight.DialogWhenLarge" parent="Theme.Material.Light.DialogWhenLarge" />
-
- <!-- Theme for a window with a dark action bar that will be displayed
- either full-screen on smaller screens (small, normal) or as a dialog
- on larger screens (large, xlarge). -->
- <style name="Theme.Material.DayNight.DialogWhenLarge.DarkActionBar" parent="Theme.Material.Light.DialogWhenLarge.DarkActionBar" />
-
- <!-- Theme for a window without an action bar that will be displayed either full-screen
- on smaller screens (small, normal) or as a dialog on larger screens
- (large, xlarge). -->
- <style name="Theme.Material.DayNight.DialogWhenLarge.NoActionBar" parent="Theme.Material.Light.DialogWhenLarge.NoActionBar" />
-
- <!-- Theme for a presentation window on a secondary display. -->
- <style name="Theme.Material.DayNight.Dialog.Presentation" parent="Theme.Material.Light.Dialog.Presentation" />
-
- <!-- Material user theme for alert dialog windows, which is used by the
- {@link android.app.AlertDialog} class. -->
- <style name="Theme.Material.DayNight.Dialog.Alert" parent="Theme.Material.DayNight.Dialog.BaseAlert" />
- <style name="Theme.Material.DayNight.Dialog.BaseAlert" parent="Theme.Material.Light.Dialog.BaseAlert" />
-
- <style name="Theme.Material.DayNight.SearchBar" parent="Theme.Material.Light.SearchBar" />
- <style name="Theme.Material.DayNight.CompactMenu" parent="Theme.Material.Light.CompactMenu" />
-
-</resources>
diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml
index 76b5fe1..2e593a3 100644
--- a/core/res/res/xml/power_profile.xml
+++ b/core/res/res/xml/power_profile.xml
@@ -94,11 +94,27 @@
<!-- This is the battery capacity in mAh (measured at nominal voltage) -->
<item name="battery.capacity">1000</item>
- <array name="wifi.batchedscan"> <!-- mA -->
- <value>.0002</value> <!-- 1-8/hr -->
- <value>.002</value> <!-- 9-64/hr -->
- <value>.02</value> <!-- 65-512/hr -->
- <value>.2</value> <!-- 513-4,096/hr -->
- <value>2</value> <!-- 4097-/hr -->
+ <!-- Wifi related values. -->
+ <!-- Idle Receive current for wifi radio in mA. 0 by default-->
+ <item name="wifi.controller.idle">0</item>
+ <!-- Rx current for wifi radio in mA. 0 by default-->
+ <item name="wifi.controller.rx">0</item>
+ <!-- Tx current for wifi radio in mA. 0 by default-->
+ <item name="wifi.controller.tx">0</item>
+ <!-- Current at each of the wifi Tx levels in mA. The number of tx levels varies per device
+ and is available only of wifi chipsets which support the tx level reporting. Use
+ wifi.tx for other chipsets. none by default -->
+ <array name="wifi.controller.tx_levels"> <!-- mA -->
</array>
+ <!-- Operating volatage for wifi radio in mV. 0 by default-->
+ <item name="wifi.controller.voltage">0</item>
+
+ <array name="wifi.batchedscan"> <!-- mA -->
+ <value>.0002</value> <!-- 1-8/hr -->
+ <value>.002</value> <!-- 9-64/hr -->
+ <value>.02</value> <!-- 65-512/hr -->
+ <value>.2</value> <!-- 513-4,096/hr -->
+ <value>2</value> <!-- 4097-/hr -->
+ </array>
+
</device>
diff --git a/core/tests/benchmarks/src/android/text/util/LinkifyBenchmark.java b/core/tests/benchmarks/src/android/text/util/LinkifyBenchmark.java
new file mode 100644
index 0000000..a6e433f
--- /dev/null
+++ b/core/tests/benchmarks/src/android/text/util/LinkifyBenchmark.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 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.text.util;
+
+import com.google.caliper.AfterExperiment;
+import com.google.caliper.BeforeExperiment;
+import com.google.caliper.Benchmark;
+import com.google.caliper.Param;
+
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.util.Patterns;
+
+import java.util.regex.Pattern;
+
+public class LinkifyBenchmark {
+ private static final String MATCHING_STR = " http://user:pass@host.com:5432/path?k=v#f " +
+ "host.com:5432/path?k=v#f ";
+
+ private static final String NONMATCHING_STR = " Neque porro quisquam est qui dolorem ipsum " +
+ "quia dolor sit amet, consectetur, adipisci velit ";
+
+ // this pattern does not recognize strings without http scheme therefore is expected to be
+ // faster in MATCHING_STR case.
+ private static final Pattern BASIC_PATTERN = Pattern.compile(
+ "(?:\\b|$|^)http://[a-zA-Z0-9:\\.@\\?=#/]+(?:\\b|$|^)");
+
+ @Param({"1", "4", "16", "64", "256"})
+ private String mParamCopyAmount;
+
+ @Param({MATCHING_STR, NONMATCHING_STR})
+ private String mParamBasicText;
+
+ private Spannable mTestSpannable;
+
+ @BeforeExperiment
+ protected void setUp() throws Exception {
+ int copyAmount = Integer.valueOf(mParamCopyAmount);
+ StringBuilder strBuilder = new StringBuilder();
+ for (int i = 0; i < copyAmount; i++) {
+ strBuilder.append(mParamBasicText);
+ }
+ mTestSpannable = new SpannableString(strBuilder.toString());
+ }
+
+ @AfterExperiment
+ protected void tearDown() {
+ mTestSpannable = null;
+ }
+
+ @Benchmark
+ public void timeNewRegEx(int reps) throws Exception {
+ for (int i = 0; i < reps; i++) {
+ Linkify.addLinks(mTestSpannable, Patterns.AUTOLINK_WEB_URL, "http://",
+ new String[]{"http://", "https://", "rtsp://"}, null, null);
+ }
+ }
+
+ @Benchmark
+ public void timeOldRegEx(int reps) throws Exception {
+ for (int i = 0; i < reps; i++) {
+ Linkify.addLinks(mTestSpannable, Patterns.WEB_URL, "http://",
+ new String[]{"http://", "https://", "rtsp://"}, null, null);
+ }
+ }
+
+ @Benchmark
+ public void timeBasicRegEx(int reps) throws Exception {
+ for (int i = 0; i < reps; i++) {
+ Linkify.addLinks(mTestSpannable, BASIC_PATTERN, "http://",
+ new String[]{"http://", "https://", "rtsp://"}, null, null);
+ }
+ }
+
+}
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index f779d6c..ecf88f1 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -675,4 +675,26 @@
assertFloatingToolbarContainsItem(
getActivity().getString(com.android.internal.R.string.copy));
}
+
+ @SmallTest
+ public void testTransientState() throws Exception {
+ final String text = "abc def";
+ onView(withId(R.id.textview)).perform(click());
+ onView(withId(R.id.textview)).perform(replaceText(text));
+
+ final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
+ assertFalse(textView.hasTransientState());
+
+ onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('b')));
+ // hasTransientState should return true when user generated selection is active.
+ assertTrue(textView.hasTransientState());
+ onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.indexOf('d')));
+ // hasTransientState should return false as the selection has been cleared.
+ assertFalse(textView.hasTransientState());
+ textView.post(
+ () -> Selection.setSelection((Spannable) textView.getText(), 0, text.length()));
+ getInstrumentation().waitForIdleSync();
+ // hasTransientState should return false when selection is created by API.
+ assertFalse(textView.hasTransientState());
+ }
}
diff --git a/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java b/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
index b8ea2de..bec4180 100644
--- a/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
+++ b/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
@@ -21,7 +21,6 @@
import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction;
import android.support.test.espresso.action.CoordinatesProvider;
-import android.support.test.espresso.action.GeneralClickAction;
import android.support.test.espresso.action.MotionEvents;
import android.support.test.espresso.action.MotionEvents.DownResultHolder;
import android.support.test.espresso.action.Press;
@@ -34,7 +33,7 @@
* ViewAction for performing an click on View by a mouse.
*/
public final class MouseClickAction implements ViewAction {
- private final GeneralClickAction mGeneralClickAction;
+ private final ViewClickAction mViewClickAction;
@MouseUiController.MouseButton
private final int mButton;
@@ -100,30 +99,22 @@
*/
public MouseClickAction(Tapper tapper, CoordinatesProvider coordinatesProvider,
@MouseUiController.MouseButton int button) {
- mGeneralClickAction = new GeneralClickAction(tapper, coordinatesProvider, Press.PINPOINT);
+ mViewClickAction = new ViewClickAction(tapper, coordinatesProvider, Press.PINPOINT);
mButton = button;
}
@Override
public Matcher<View> getConstraints() {
- return mGeneralClickAction.getConstraints();
+ return mViewClickAction.getConstraints();
}
@Override
public String getDescription() {
- return mGeneralClickAction.getDescription();
+ return mViewClickAction.getDescription();
}
@Override
public void perform(UiController uiController, View view) {
- mGeneralClickAction.perform(new MouseUiController(uiController, mButton), view);
- long doubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
- if (0 < doubleTapTimeout) {
- // Wait to avoid false gesture detection. Without this wait, consecutive clicks can be
- // detected as a triple click. e.g. 2 double clicks are detected as a triple click and
- // a single click because espresso isn't aware of triple click detection logic, which
- // is TextView specific gesture.
- uiController.loopMainThreadForAtLeast(doubleTapTimeout);
- }
+ mViewClickAction.perform(new MouseUiController(uiController, mButton), view);
}
}
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
index 4cecb65..335d021 100644
--- a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
@@ -17,15 +17,10 @@
package android.widget.espresso;
import static android.support.test.espresso.action.ViewActions.actionWithAssertions;
-
-import org.hamcrest.core.Is;
-import org.hamcrest.core.IsInstanceOf;
-
import android.graphics.Rect;
import android.support.test.espresso.PerformException;
import android.support.test.espresso.ViewAction;
import android.support.test.espresso.action.CoordinatesProvider;
-import android.support.test.espresso.action.GeneralClickAction;
import android.support.test.espresso.action.Press;
import android.support.test.espresso.action.Tap;
import android.support.test.espresso.util.HumanReadables;
@@ -55,7 +50,7 @@
*/
public static ViewAction clickOnTextAtIndex(int index) {
return actionWithAssertions(
- new GeneralClickAction(Tap.SINGLE, new TextCoordinates(index), Press.FINGER));
+ new ViewClickAction(Tap.SINGLE, new TextCoordinates(index), Press.FINGER));
}
/**
@@ -101,7 +96,7 @@
*/
public static ViewAction doubleClickOnTextAtIndex(int index) {
return actionWithAssertions(
- new GeneralClickAction(Tap.DOUBLE, new TextCoordinates(index), Press.FINGER));
+ new ViewClickAction(Tap.DOUBLE, new TextCoordinates(index), Press.FINGER));
}
/**
@@ -131,7 +126,7 @@
*/
public static ViewAction longPressOnTextAtIndex(int index) {
return actionWithAssertions(
- new GeneralClickAction(Tap.LONG, new TextCoordinates(index), Press.FINGER));
+ new ViewClickAction(Tap.LONG, new TextCoordinates(index), Press.FINGER));
}
/**
diff --git a/core/tests/coretests/src/android/widget/espresso/ViewClickAction.java b/core/tests/coretests/src/android/widget/espresso/ViewClickAction.java
new file mode 100644
index 0000000..8bce1b0
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/espresso/ViewClickAction.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 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.widget.espresso;
+
+import org.hamcrest.Matcher;
+
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.support.test.espresso.action.CoordinatesProvider;
+import android.support.test.espresso.action.GeneralClickAction;
+import android.support.test.espresso.action.PrecisionDescriber;
+import android.support.test.espresso.action.Tapper;
+import android.view.View;
+import android.view.ViewConfiguration;
+
+public final class ViewClickAction implements ViewAction {
+ private final GeneralClickAction mGeneralClickAction;
+
+ public ViewClickAction(Tapper tapper, CoordinatesProvider coordinatesProvider,
+ PrecisionDescriber precisionDescriber) {
+ mGeneralClickAction = new GeneralClickAction(tapper, coordinatesProvider,
+ precisionDescriber);
+ }
+
+ @Override
+ public Matcher<View> getConstraints() {
+ return mGeneralClickAction.getConstraints();
+ }
+
+ @Override
+ public String getDescription() {
+ return mGeneralClickAction.getDescription();
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ mGeneralClickAction.perform(uiController, view);
+ long doubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
+ if (0 < doubleTapTimeout) {
+ // Wait to avoid false gesture detection. Without this wait, consecutive clicks can be
+ // detected as a double click or triple click. e.g. 2 double clicks on TextView are
+ // detected as a triple click and a single click because espresso isn't aware of
+ // TextView specific gestures.
+ uiController.loopMainThreadForAtLeast(doubleTapTimeout);
+ }
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
index 7519627..2a24881 100644
--- a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
+++ b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
@@ -22,7 +22,6 @@
import android.view.ActionMode;
import android.view.ActionMode.Callback;
import android.view.KeyEvent;
-import android.view.KeyboardShortcutGroup;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index fd28f64..f4c5b53 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -101,8 +101,13 @@
checkbuild: fontchain_lint
FONTCHAIN_LINTER := frameworks/base/tools/fonts/fontchain_lint.py
+ifeq ($(SMALLER_FONT_FOOTPRINT),true)
+CHECK_EMOJI := false
+else
+CHECK_EMOJI := true
+endif
.PHONY: fontchain_lint
-fontchain_lint: $(FONTCHAIN_LINTER) $(TARGET_OUT)/etc/fonts.xml
+fontchain_lint: $(FONTCHAIN_LINTER) $(TARGET_OUT)/etc/fonts.xml $(PRODUCT_OUT)/system.img
PYTHONPATH=$$PYTHONPATH:external/fonttools/Lib \
- python $(FONTCHAIN_LINTER) $(TARGET_OUT) external/unicode
+ python $(FONTCHAIN_LINTER) $(TARGET_OUT) $(CHECK_EMOJI) external/unicode
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index 3973f2f..aa81b91 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -37,22 +37,26 @@
public final class Outline {
private static final float RADIUS_UNDEFINED = Float.NEGATIVE_INFINITY;
- private static final int MODE_EMPTY = 0;
- private static final int MODE_RECT = 1;
- private static final int MODE_CONVEX_PATH = 2;
+ /** @hide */
+ public static final int MODE_EMPTY = 0;
+ /** @hide */
+ public static final int MODE_ROUND_RECT = 1;
+ /** @hide */
+ public static final int MODE_CONVEX_PATH = 2;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = false,
value = {
MODE_EMPTY,
- MODE_RECT,
+ MODE_ROUND_RECT,
MODE_CONVEX_PATH,
})
public @interface Mode {}
+ /** @hide */
@Mode
- private int mMode = MODE_EMPTY;
+ public int mMode = MODE_EMPTY;
/** @hide */
public final Path mPath = new Path();
@@ -176,7 +180,7 @@
return;
}
- mMode = MODE_RECT;
+ mMode = MODE_ROUND_RECT;
mRect.set(left, top, right, bottom);
mRadius = radius;
mPath.rewind();
@@ -199,7 +203,7 @@
* bounds, or {@code false} if no outline bounds are set
*/
public boolean getRect(@NonNull Rect outRect) {
- if (mMode != MODE_RECT) {
+ if (mMode != MODE_ROUND_RECT) {
return false;
}
outRect.set(mRect);
@@ -270,7 +274,7 @@
* Offsets the Outline by (dx,dy)
*/
public void offset(int dx, int dy) {
- if (mMode == MODE_RECT) {
+ if (mMode == MODE_ROUND_RECT) {
mRect.offset(dx, dy);
} else if (mMode == MODE_CONVEX_PATH) {
mPath.offset(dx, dy);
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 46a0f43..35385eb 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -1416,6 +1416,9 @@
Log.d(LOGTAG, "on finished called from native");
}
mStarted = false;
+ // Invalidate in the end of the animation to make sure the data in
+ // RT thread is synced back to UI thread.
+ invalidateOwningView();
if (mListener != null) {
mListener.onAnimationEnd(null);
}
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 1f17851..be816f78 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -252,6 +252,7 @@
tests/unit/LinearAllocatorTests.cpp \
tests/unit/MatrixTests.cpp \
tests/unit/OffscreenBufferPoolTests.cpp \
+ tests/unit/RenderNodeTests.cpp \
tests/unit/SkiaBehaviorTests.cpp \
tests/unit/StringUtilsTests.cpp \
tests/unit/TextDropShadowCacheTests.cpp \
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index ea4f4eb..5fb8425 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -195,7 +195,7 @@
}
static void renderTextShadow(BakedOpRenderer& renderer, FontRenderer& fontRenderer,
- const TextOp& op, const BakedOpState& state) {
+ const TextOp& op, const BakedOpState& textOpState) {
renderer.caches().textureState().activateTexture(0);
PaintUtils::TextShadow textShadow;
@@ -216,13 +216,41 @@
Glop glop;
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
- .setRoundRectClipState(state.roundRectClipState)
+ .setRoundRectClipState(textOpState.roundRectClipState)
.setMeshTexturedUnitQuad(nullptr)
- .setFillShadowTexturePaint(*texture, textShadow.color, *op.paint, state.alpha)
- .setTransform(state.computedState.transform, TransformFlags::None)
+ .setFillShadowTexturePaint(*texture, textShadow.color, *op.paint, textOpState.alpha)
+ .setTransform(textOpState.computedState.transform, TransformFlags::None)
.setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width(), sy + texture->height()))
.build();
- renderer.renderGlop(state, glop);
+
+ // Compute damage bounds and clip (since may differ from those in textOpState).
+ // Bounds should be same as text op, but with dx/dy offset and radius outset
+ // applied in local space.
+ auto& transform = textOpState.computedState.transform;
+ Rect shadowBounds = op.unmappedBounds; // STROKE
+ const bool expandForStroke = op.paint->getStyle() != SkPaint::kFill_Style;
+ if (expandForStroke) {
+ shadowBounds.outset(op.paint->getStrokeWidth() * 0.5f);
+ }
+ shadowBounds.translate(textShadow.dx, textShadow.dy);
+ shadowBounds.outset(textShadow.radius, textShadow.radius);
+ transform.mapRect(shadowBounds);
+ if (CC_UNLIKELY(expandForStroke &&
+ (!transform.isPureTranslate() || op.paint->getStrokeWidth() < 1.0f))) {
+ shadowBounds.outset(0.5f);
+ }
+
+ auto clipState = textOpState.computedState.clipState;
+ if (clipState->mode != ClipMode::Rectangle
+ || !clipState->rect.contains(shadowBounds)) {
+ // need clip, so pass it and clip bounds
+ shadowBounds.doIntersect(clipState->rect);
+ } else {
+ // don't need clip, ignore
+ clipState = nullptr;
+ }
+
+ renderer.renderGlop(&shadowBounds, clipState, glop);
}
enum class TextRenderType {
@@ -781,10 +809,6 @@
Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight()))
.build();
renderer.renderGlop(state, glop);
-
- if (op.destroy) {
- renderer.renderState().layerPool().putOrDelete(buffer);
- }
}
}
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
index 20f102b..3c302b3 100644
--- a/libs/hwui/BakedOpRenderer.cpp
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -37,6 +37,10 @@
return buffer;
}
+void BakedOpRenderer::recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) {
+ mRenderState.layerPool().putOrDelete(offscreenBuffer);
+}
+
void BakedOpRenderer::startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) {
LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer...");
diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h
index 1b4065a..62bc564 100644
--- a/libs/hwui/BakedOpRenderer.h
+++ b/libs/hwui/BakedOpRenderer.h
@@ -69,6 +69,7 @@
void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect);
void endFrame(const Rect& repaintRect);
WARN_UNUSED_RESULT OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height);
+ void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer);
void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect);
void endLayer();
WARN_UNUSED_RESULT OffscreenBuffer* copyToLayer(const Rect& area);
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 59f0d7c..181b343 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -45,6 +45,7 @@
, regions(stdAllocator)
, referenceHolders(stdAllocator)
, functors(stdAllocator)
+ , pushStagingFunctors(stdAllocator)
, hasDrawOps(false) {
}
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 60cc7ba..e209e2a 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -110,6 +110,16 @@
};
/**
+ * Functor that can be used for objects with data in both UI thread and RT to keep the data
+ * in sync. This functor, when added to DisplayList, will be call during DisplayList sync.
+ */
+struct PushStagingFunctor {
+ PushStagingFunctor() {}
+ virtual ~PushStagingFunctor() {}
+ virtual void operator ()() {}
+};
+
+/**
* Data structure that holds the list of commands used in display list stream
*/
class DisplayList {
@@ -142,6 +152,7 @@
const LsaVector<const SkBitmap*>& getBitmapResources() const { return bitmapResources; }
const LsaVector<Functor*>& getFunctors() const { return functors; }
+ const LsaVector<PushStagingFunctor*>& getPushStagingFunctors() { return pushStagingFunctors; }
size_t addChild(NodeOpType* childOp);
@@ -183,6 +194,11 @@
// List of functors
LsaVector<Functor*> functors;
+ // List of functors that need to be notified of pushStaging. Note that this list gets nothing
+ // but a callback during sync DisplayList, unlike the list of functors defined above, which
+ // gets special treatment exclusive for webview.
+ LsaVector<PushStagingFunctor*> pushStagingFunctors;
+
bool hasDrawOps; // only used if !HWUI_NEW_OPS
void cleanupResources();
diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp
index 2dccf32..c6e92ab 100644
--- a/libs/hwui/DisplayListCanvas.cpp
+++ b/libs/hwui/DisplayListCanvas.cpp
@@ -415,7 +415,8 @@
void DisplayListCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
mDisplayList->ref(tree);
- addDrawOp(new (alloc()) DrawVectorDrawableOp(tree));
+ mDisplayList->pushStagingFunctors.push_back(tree->getFunctor());
+ addDrawOp(new (alloc()) DrawVectorDrawableOp(tree, tree->stagingProperties()->getBounds()));
}
void DisplayListCanvas::drawGlyphsOnPath(const uint16_t* glyphs, int count,
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 516e619..59f073f 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -1110,15 +1110,14 @@
class DrawVectorDrawableOp : public DrawOp {
public:
- DrawVectorDrawableOp(VectorDrawableRoot* tree)
- : DrawOp(nullptr), mTree(tree) {}
+ DrawVectorDrawableOp(VectorDrawableRoot* tree, const SkRect& bounds)
+ : DrawOp(nullptr), mTree(tree), mDst(bounds) {}
virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
const SkBitmap& bitmap = mTree->getBitmapUpdateIfDirty();
SkPaint* paint = mTree->getPaint();
- const SkRect bounds = mTree->getBounds();
renderer.drawBitmap(&bitmap, Rect(0, 0, bitmap.width(), bitmap.height()),
- bounds, paint);
+ mDst, paint);
}
virtual void output(int level, uint32_t logFlags) const override {
@@ -1129,6 +1128,7 @@
private:
VectorDrawableRoot* mTree;
+ SkRect mDst;
};
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index 9c46c00..0401f2d 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -522,7 +522,10 @@
void FrameBuilder::deferBitmapOp(const BitmapOp& op) {
BakedOpState* bakedState = tryBakeOpState(op);
if (!bakedState) return; // quick rejected
- bakedState->setupOpacity(op.paint);
+
+ if (op.bitmap->isOpaque()) {
+ bakedState->setupOpacity(op.paint);
+ }
// Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation
// Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in
diff --git a/libs/hwui/FrameBuilder.h b/libs/hwui/FrameBuilder.h
index e418227..039ab6b 100644
--- a/libs/hwui/FrameBuilder.h
+++ b/libs/hwui/FrameBuilder.h
@@ -86,6 +86,7 @@
*/
template <typename StaticDispatcher, typename Renderer>
void replayBakedOps(Renderer& renderer) {
+ std::vector<OffscreenBuffer*> temporaryLayers;
finishDefer();
/**
* Defines a LUT of lambdas which allow a recorded BakedOpState to use state->op->opId to
@@ -129,6 +130,7 @@
} else if (!layer.empty()) {
// save layer - skip entire layer if empty (in which case, LayerOp has null layer).
layer.offscreenBuffer = renderer.startTemporaryLayer(layer.width, layer.height);
+ temporaryLayers.push_back(layer.offscreenBuffer);
GL_CHECKPOINT(MODERATE);
layer.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers);
GL_CHECKPOINT(MODERATE);
@@ -145,6 +147,10 @@
GL_CHECKPOINT(MODERATE);
renderer.endFrame(fbo0.repaintRect);
}
+
+ for (auto& temporaryLayer : temporaryLayers) {
+ renderer.recycleTemporaryLayer(temporaryLayer);
+ }
}
void dump() const {
diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h
index 704bd69..6a96634 100644
--- a/libs/hwui/Glop.h
+++ b/libs/hwui/Glop.h
@@ -163,11 +163,13 @@
GLenum dst;
} blend;
+#if !HWUI_NEW_OPS
/**
* Bounds of the drawing command in layer space. Only mapped into layer
* space once GlopBuilder::build() is called.
*/
Rect bounds; // TODO: remove for HWUI_NEW_OPS
+#endif
/**
* Additional render state to enumerate:
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index 2799def..7d4f410 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -492,7 +492,9 @@
mOutGlop->transform.modelView.loadTranslate(destination.left, destination.top, 0.0f);
mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
+#if !HWUI_NEW_OPS
mOutGlop->bounds = destination;
+#endif
return *this;
}
@@ -516,7 +518,9 @@
mOutGlop->transform.modelView.loadTranslate(left, top, 0.0f);
mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
+#if !HWUI_NEW_OPS
mOutGlop->bounds = destination;
+#endif
return *this;
}
@@ -524,8 +528,10 @@
TRIGGER_STAGE(kModelViewStage);
mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f);
+#if !HWUI_NEW_OPS
mOutGlop->bounds = source;
mOutGlop->bounds.translate(offsetX, offsetY);
+#endif
return *this;
}
@@ -545,8 +551,10 @@
}
mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f);
+#if !HWUI_NEW_OPS
mOutGlop->bounds = source;
mOutGlop->bounds.translate(offsetX, offsetY);
+#endif
return *this;
}
@@ -643,7 +651,9 @@
// Final step: populate program and map bounds into render target space
mOutGlop->fill.program = mCaches.programCache.get(mDescription);
+#if !HWUI_NEW_OPS
mOutGlop->transform.meshTransform().mapRect(mOutGlop->bounds);
+#endif
}
void GlopBuilder::dump(const Glop& glop) {
@@ -683,7 +693,9 @@
ALOGD_IF(glop.roundRectClipState, "Glop RRCS %p", glop.roundRectClipState);
ALOGD("Glop blend %d %d", glop.blend.src, glop.blend.dst);
+#if !HWUI_NEW_OPS
ALOGD("Glop bounds " RECT_STRING, RECT_ARGS(glop.bounds));
+#endif
}
} /* namespace uirenderer */
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index 47d0108..d1ff670 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -56,24 +56,17 @@
static const int64_t IGNORE_EXCEEDING = seconds_to_nanoseconds(10);
/*
- * Frames that are exempt from jank metrics.
- * First-draw frames, for example, are expected to
- * be slow, this is hidden from the user with window animations and
- * other tricks
- *
- * Similarly, we don't track direct-drawing via Surface:lockHardwareCanvas()
+ * We don't track direct-drawing via Surface:lockHardwareCanvas()
* for now
*
* TODO: kSurfaceCanvas can negatively impact other drawing by using up
* time on the RenderThread, figure out how to attribute that as a jank-causer
*/
-static const int64_t EXEMPT_FRAMES_FLAGS
- = FrameInfoFlags::WindowLayoutChanged
- | FrameInfoFlags::SurfaceCanvas;
+static const int64_t EXEMPT_FRAMES_FLAGS = FrameInfoFlags::SurfaceCanvas;
// The bucketing algorithm controls so to speak
// If a frame is <= to this it goes in bucket 0
-static const uint32_t kBucketMinThreshold = 7;
+static const uint32_t kBucketMinThreshold = 5;
// If a frame is > this, start counting in increments of 2ms
static const uint32_t kBucket2msIntervals = 32;
// If a frame is > this, start counting in increments of 4ms
@@ -84,9 +77,14 @@
// and filter it out of the frame profile data
static FrameInfoIndex sFrameStart = FrameInfoIndex::IntendedVsync;
+// The interval of the slow frame histogram
+static const uint32_t kSlowFrameBucketIntervalMs = 50;
+// The start point of the slow frame bucket in ms
+static const uint32_t kSlowFrameBucketStartMs = 150;
+
// This will be called every frame, performance sensitive
// Uses bit twiddling to avoid branching while achieving the packing desired
-static uint32_t frameCountIndexForFrameTime(nsecs_t frameTime, uint32_t max) {
+static uint32_t frameCountIndexForFrameTime(nsecs_t frameTime) {
uint32_t index = static_cast<uint32_t>(ns2ms(frameTime));
// If index > kBucketMinThreshold mask will be 0xFFFFFFFF as a result
// of negating 1 (twos compliment, yaay) else mask will be 0
@@ -104,7 +102,7 @@
// be a pretty garbage value right now. However, mask is 0 so we'll end
// up with the desired result of 0.
index = (index - kBucketMinThreshold) & mask;
- return index < max ? index : max;
+ return index;
}
// Only called when dumping stats, less performance sensitive
@@ -211,63 +209,34 @@
}
-static bool shouldReplace(SlowFrame& existing, SlowFrame& candidate) {
- if (candidate.whenHours - existing.whenHours >= 24) {
- // If the old slowframe is over 24 hours older than the candidate,
- // replace it. It's too stale
- return true;
- }
- if (candidate.frametimeMs > existing.frametimeMs) {
- return true;
- }
- return false;
-}
-
-void JankTracker::updateSlowest(const FrameInfo& frame) {
- uint16_t durationMs = static_cast<uint16_t>(std::min(
- ns2ms(frame[FrameInfoIndex::FrameCompleted] - frame[FrameInfoIndex::IntendedVsync]),
- static_cast<nsecs_t>(std::numeric_limits<uint16_t>::max())));
- uint16_t startHours = static_cast<uint16_t>(std::lround(
- ns2s(frame[FrameInfoIndex::IntendedVsync]) / 3600.0f));
- SlowFrame* toReplace = nullptr;
- SlowFrame thisFrame{startHours, durationMs};
- // First find the best candidate for replacement
- for (SlowFrame& existing : mData->slowestFrames) {
- // If we should replace the current data with the replacement candidate,
- // it means the current data is worse than the replacement candidate
- if (!toReplace || shouldReplace(existing, *toReplace)) {
- toReplace = &existing;
- }
- }
- // Now see if we should replace it
- if (shouldReplace(*toReplace, thisFrame)) {
- *toReplace = thisFrame;
- }
-}
-
void JankTracker::addFrame(const FrameInfo& frame) {
mData->totalFrameCount++;
// Fast-path for jank-free frames
int64_t totalDuration =
frame[FrameInfoIndex::FrameCompleted] - frame[sFrameStart];
- uint32_t framebucket = frameCountIndexForFrameTime(
- totalDuration, mData->frameCounts.size() - 1);
+ uint32_t framebucket = frameCountIndexForFrameTime(totalDuration);
// Keep the fast path as fast as possible.
if (CC_LIKELY(totalDuration < mFrameInterval)) {
mData->frameCounts[framebucket]++;
return;
}
- // For slowest frames we are still interested in frames that are otherwise
- // exempt (such as first-draw). Although those frames don't directly impact
- // smoothness, they do impact responsiveness.
- updateSlowest(frame);
-
+ // Only things like Surface.lockHardwareCanvas() are exempt from tracking
if (frame[FrameInfoIndex::Flags] & EXEMPT_FRAMES_FLAGS) {
return;
}
- mData->frameCounts[framebucket]++;
+ if (framebucket <= mData->frameCounts.size()) {
+ mData->frameCounts[framebucket]++;
+ } else {
+ framebucket = (ns2ms(totalDuration) - kSlowFrameBucketStartMs)
+ / kSlowFrameBucketIntervalMs;
+ framebucket = std::min(framebucket,
+ static_cast<uint32_t>(mData->slowFrameCounts.size() - 1));
+ framebucket = std::max(framebucket, 0u);
+ mData->slowFrameCounts[framebucket]++;
+ }
+
mData->jankFrameCount++;
for (int i = 0; i < NUM_BUCKETS; i++) {
@@ -298,14 +267,18 @@
dprintf(fd, "\n90th percentile: %ums", findPercentile(data, 90));
dprintf(fd, "\n95th percentile: %ums", findPercentile(data, 95));
dprintf(fd, "\n99th percentile: %ums", findPercentile(data, 99));
- dprintf(fd, "\nSlowest frames over last 24h: ");
- for (auto& slowFrame : data->slowestFrames) {
- if (!slowFrame.frametimeMs) continue;
- dprintf(fd, "%ums ", slowFrame.frametimeMs);
- }
for (int i = 0; i < NUM_BUCKETS; i++) {
dprintf(fd, "\nNumber %s: %u", JANK_TYPE_NAMES[i], data->jankTypeCounts[i]);
}
+ dprintf(fd, "\nHISTOGRAM:");
+ for (size_t i = 0; i < data->frameCounts.size(); i++) {
+ dprintf(fd, " %ums=%u", frameTimeForFrameCountIndex(i),
+ data->frameCounts[i]);
+ }
+ for (size_t i = 0; i < data->slowFrameCounts.size(); i++) {
+ dprintf(fd, " %zums=%u", (i * kSlowFrameBucketIntervalMs) + kSlowFrameBucketStartMs,
+ data->slowFrameCounts[i]);
+ }
dprintf(fd, "\n");
}
@@ -323,6 +296,12 @@
uint32_t JankTracker::findPercentile(const ProfileData* data, int percentile) {
int pos = percentile * data->totalFrameCount / 100;
int remaining = data->totalFrameCount - pos;
+ for (int i = data->slowFrameCounts.size() - 1; i >= 0; i--) {
+ remaining -= data->slowFrameCounts[i];
+ if (remaining <= 0) {
+ return (i * kSlowFrameBucketIntervalMs) + kSlowFrameBucketStartMs;
+ }
+ }
for (int i = data->frameCounts.size() - 1; i >= 0; i--) {
remaining -= data->frameCounts[i];
if (remaining <= 0) {
diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h
index 1a4a489..84b8c3f 100644
--- a/libs/hwui/JankTracker.h
+++ b/libs/hwui/JankTracker.h
@@ -39,23 +39,18 @@
NUM_BUCKETS,
};
-struct SlowFrame {
- uint16_t whenHours; // When this occurred in CLOCK_MONOTONIC in hours
- uint16_t frametimeMs; // How long the frame took in ms
-};
-
// Try to keep as small as possible, should match ASHMEM_SIZE in
// GraphicsStatsService.java
struct ProfileData {
std::array<uint32_t, NUM_BUCKETS> jankTypeCounts;
// See comments on kBucket* constants for what this holds
- std::array<uint32_t, 55> frameCounts;
+ std::array<uint32_t, 57> frameCounts;
+ // Holds a histogram of frame times in 50ms increments from 150ms to 5s
+ std::array<uint16_t, 97> slowFrameCounts;
uint32_t totalFrameCount;
uint32_t jankFrameCount;
nsecs_t statStartTime;
-
- std::array<SlowFrame, 10> slowestFrames;
};
// TODO: Replace DrawProfiler with this
@@ -78,7 +73,6 @@
private:
void freeData();
void setFrameInterval(nsecs_t frameIntervalNanos);
- void updateSlowest(const FrameInfo& frame);
static uint32_t findPercentile(const ProfileData* data, int p);
static void dumpData(const ProfileData* data, int fd);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index c099427..53ea7fa 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1413,7 +1413,9 @@
if (type == GlopRenderType::Standard && !mRenderState.stencil().isWriteEnabled()) {
// TODO: specify more clearly when a draw should dirty the layer.
// is writing to the stencil the only time we should ignore this?
+#if !HWUI_NEW_OPS
dirtyLayer(glop.bounds.left, glop.bounds.top, glop.bounds.right, glop.bounds.bottom);
+#endif
mDirty = true;
}
}
diff --git a/libs/hwui/PropertyValuesHolder.cpp b/libs/hwui/PropertyValuesHolder.cpp
index 8f837f6..0932d65 100644
--- a/libs/hwui/PropertyValuesHolder.cpp
+++ b/libs/hwui/PropertyValuesHolder.cpp
@@ -53,7 +53,7 @@
} else {
animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction;
}
- mGroup->setPropertyValue(mPropertyId, animatedValue);
+ mGroup->mutateProperties()->setPropertyValue(mPropertyId, animatedValue);
}
inline U8CPU lerp(U8CPU fromValue, U8CPU toValue, float fraction) {
@@ -72,7 +72,7 @@
void FullPathColorPropertyValuesHolder::setFraction(float fraction) {
SkColor animatedValue = interpolateColors(mStartValue, mEndValue, fraction);
- mFullPath->setColorPropertyValue(mPropertyId, animatedValue);
+ mFullPath->mutateProperties()->setColorPropertyValue(mPropertyId, animatedValue);
}
void FullPathPropertyValuesHolder::setFraction(float fraction) {
@@ -82,17 +82,17 @@
} else {
animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction;
}
- mFullPath->setPropertyValue(mPropertyId, animatedValue);
+ mFullPath->mutateProperties()->setPropertyValue(mPropertyId, animatedValue);
}
void PathDataPropertyValuesHolder::setFraction(float fraction) {
VectorDrawableUtils::interpolatePaths(&mPathData, mStartValue, mEndValue, fraction);
- mPath->setPathData(mPathData);
+ mPath->mutateProperties()->setData(mPathData);
}
void RootAlphaPropertyValuesHolder::setFraction(float fraction) {
float animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction;
- mTree->setRootAlpha(animatedValue);
+ mTree->mutateProperties()->setRootAlpha(animatedValue);
}
} // namepace uirenderer
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index 0271a80..aee9d63 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -501,22 +501,20 @@
* when creating/tracking a SkPaint* during defer isn't worth the bother.
*/
struct LayerOp : RecordedOp {
- // Records a one-use (saveLayer) layer for drawing. Once drawn, the layer will be destroyed.
+ // Records a one-use (saveLayer) layer for drawing.
LayerOp(BASE_PARAMS, OffscreenBuffer** layerHandle)
: SUPER_PAINTLESS(LayerOp)
, layerHandle(layerHandle)
, alpha(paint ? paint->getAlpha() / 255.0f : 1.0f)
, mode(PaintUtils::getXfermodeDirect(paint))
- , colorFilter(paint ? paint->getColorFilter() : nullptr)
- , destroy(true) {}
+ , colorFilter(paint ? paint->getColorFilter() : nullptr) {}
LayerOp(RenderNode& node)
: RecordedOp(RecordedOpId::LayerOp, Rect(node.getWidth(), node.getHeight()), Matrix4::identity(), nullptr, nullptr)
, layerHandle(node.getLayerHandle())
, alpha(node.properties().layerProperties().alpha() / 255.0f)
, mode(node.properties().layerProperties().xferMode())
- , colorFilter(node.properties().layerProperties().colorFilter())
- , destroy(false) {}
+ , colorFilter(node.properties().layerProperties().colorFilter()) {}
// Records a handle to the Layer object, since the Layer itself won't be
// constructed until after this operation is constructed.
@@ -527,9 +525,6 @@
// pointer to object owned by either LayerProperties, or a recorded Paint object in a
// BeginLayerOp. Lives longer than LayerOp in either case, so no skia ref counting is used.
SkColorFilter* colorFilter;
-
- // whether to destroy the layer, once rendered
- const bool destroy;
};
}; // namespace uirenderer
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 4f9cd68..b78497d 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -430,10 +430,11 @@
}
void RecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
+ mDisplayList->pushStagingFunctors.push_back(tree->getFunctor());
mDisplayList->ref(tree);
addOp(alloc().create_trivial<VectorDrawableOp>(
tree,
- Rect(tree->getBounds()),
+ Rect(tree->stagingProperties()->getBounds()),
*(mState.currentSnapshot()->transform),
getRecordedClip()));
}
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 61441ce..9578486 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -68,7 +68,7 @@
}
RenderNode::~RenderNode() {
- deleteDisplayList();
+ deleteDisplayList(nullptr);
delete mStagingDisplayList;
#if HWUI_NEW_OPS
LOG_ALWAYS_FATAL_IF(mLayer, "layer missed detachment!");
@@ -88,7 +88,7 @@
// If mParentCount == 0 we are the sole reference to this RenderNode,
// so immediately free the old display list
if (!mParentCount && !mStagingDisplayList) {
- deleteDisplayList();
+ deleteDisplayList(nullptr);
}
}
@@ -462,7 +462,7 @@
}
#endif
-void RenderNode::syncDisplayList() {
+void RenderNode::syncDisplayList(TreeObserver* observer) {
// Make sure we inc first so that we don't fluctuate between 0 and 1,
// which would thrash the layer cache
if (mStagingDisplayList) {
@@ -470,13 +470,16 @@
child->renderNode->incParentRefCount();
}
}
- deleteDisplayList();
+ deleteDisplayList(observer);
mDisplayList = mStagingDisplayList;
mStagingDisplayList = nullptr;
if (mDisplayList) {
for (size_t i = 0; i < mDisplayList->getFunctors().size(); i++) {
(*mDisplayList->getFunctors()[i])(DrawGlInfo::kModeSync, nullptr);
}
+ for (size_t i = 0; i < mDisplayList->getPushStagingFunctors().size(); i++) {
+ (*mDisplayList->getPushStagingFunctors()[i])();
+ }
}
}
@@ -486,15 +489,15 @@
// Damage with the old display list first then the new one to catch any
// changes in isRenderable or, in the future, bounds
damageSelf(info);
- syncDisplayList();
+ syncDisplayList(info.observer);
damageSelf(info);
}
}
-void RenderNode::deleteDisplayList() {
+void RenderNode::deleteDisplayList(TreeObserver* observer) {
if (mDisplayList) {
for (auto&& child : mDisplayList->getChildren()) {
- child->renderNode->decParentRefCount();
+ child->renderNode->decParentRefCount(observer);
}
}
delete mDisplayList;
@@ -526,32 +529,35 @@
}
}
-void RenderNode::destroyHardwareResources() {
+void RenderNode::destroyHardwareResources(TreeObserver* observer) {
if (mLayer) {
destroyLayer(mLayer);
mLayer = nullptr;
}
if (mDisplayList) {
for (auto&& child : mDisplayList->getChildren()) {
- child->renderNode->destroyHardwareResources();
+ child->renderNode->destroyHardwareResources(observer);
}
if (mNeedsDisplayListSync) {
// Next prepare tree we are going to push a new display list, so we can
// drop our current one now
- deleteDisplayList();
+ deleteDisplayList(observer);
}
}
}
-void RenderNode::decParentRefCount() {
+void RenderNode::decParentRefCount(TreeObserver* observer) {
LOG_ALWAYS_FATAL_IF(!mParentCount, "already 0!");
mParentCount--;
if (!mParentCount) {
+ if (observer) {
+ observer->onMaybeRemovedFromTree(this);
+ }
// If a child of ours is being attached to our parent then this will incorrectly
// destroy its hardware resources. However, this situation is highly unlikely
// and the failure is "just" that the layer is re-created, so this should
// be safe enough
- destroyHardwareResources();
+ destroyHardwareResources(observer);
}
}
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 8381925..b0136cf 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -68,6 +68,7 @@
class SaveOp;
class RestoreToCountOp;
class TreeInfo;
+class TreeObserver;
namespace proto {
class RenderNode;
@@ -154,6 +155,14 @@
}
}
+ VirtualLightRefBase* getUserContext() const {
+ return mUserContext.get();
+ }
+
+ void setUserContext(VirtualLightRefBase* context) {
+ mUserContext = context;
+ }
+
bool isPropertyFieldDirty(DirtyPropertyMask field) const {
return mDirtyPropertyFields & field;
}
@@ -187,7 +196,7 @@
}
ANDROID_API virtual void prepareTree(TreeInfo& info);
- void destroyHardwareResources();
+ void destroyHardwareResources(TreeObserver* observer);
// UI thread only!
ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
@@ -232,6 +241,12 @@
mPositionListener.reset(listener);
}
+ // This is only modified in MODE_FULL, so it can be safely accessed
+ // on the UI thread.
+ ANDROID_API bool hasParents() {
+ return mParentCount;
+ }
+
private:
typedef key_value_pair_t<float, DrawRenderNodeOp*> ZDrawRenderNodeOpPair;
@@ -291,7 +306,7 @@
void syncProperties();
- void syncDisplayList();
+ void syncDisplayList(TreeObserver* observer);
void prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer);
void pushStagingPropertiesChanges(TreeInfo& info);
@@ -302,13 +317,14 @@
#endif
void prepareLayer(TreeInfo& info, uint32_t dirtyMask);
void pushLayerUpdate(TreeInfo& info);
- void deleteDisplayList();
+ void deleteDisplayList(TreeObserver* observer);
void damageSelf(TreeInfo& info);
void incParentRefCount() { mParentCount++; }
- void decParentRefCount();
+ void decParentRefCount(TreeObserver* observer);
String8 mName;
+ sp<VirtualLightRefBase> mUserContext;
uint32_t mDirtyPropertyFields;
RenderProperties mProperties;
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index f577785..5ebf545 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -155,6 +155,23 @@
ALOGD("%*s(ClipRect %d, %d, %d, %d)", level * 2, "",
(int)clipRect.left, (int)clipRect.top, (int)clipRect.right, (int)clipRect.bottom);
}
+
+ if (getRevealClip().willClip()) {
+ Rect bounds;
+ getRevealClip().getBounds(&bounds);
+ ALOGD("%*s(Clip to reveal clip with bounds %.2f %.2f %.2f %.2f)", level * 2, "",
+ RECT_ARGS(bounds));
+ }
+
+ auto& outline = mPrimitiveFields.mOutline;
+ if (outline.getShouldClip()) {
+ if (outline.isEmpty()) {
+ ALOGD("%*s(Clip to empty outline)", level * 2, "");
+ } else if (outline.willClip()) {
+ ALOGD("%*s(Clip to outline with bounds %.2f %.2f %.2f %.2f)", level * 2, "",
+ RECT_ARGS(outline.getBounds()));
+ }
+ }
}
void RenderProperties::updateMatrix() {
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 5d24fa0..1b459c1 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -747,11 +747,7 @@
}
void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) {
- const SkBitmap& bitmap = vectorDrawable->getBitmapUpdateIfDirty();
- SkRect bounds = vectorDrawable->getBounds();
- drawBitmap(bitmap, 0, 0, bitmap.width(), bitmap.height(),
- bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom,
- vectorDrawable->getPaint());
+ vectorDrawable->drawStaging(this);
}
// ----------------------------------------------------------------------------
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index accd303..a43e544 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -32,6 +32,7 @@
class DamageAccumulator;
class LayerUpdateQueue;
class OpenGLRenderer;
+class RenderNode;
class RenderState;
class ErrorHandler {
@@ -41,6 +42,17 @@
~ErrorHandler() {}
};
+class TreeObserver {
+public:
+ // Called when a RenderNode's parent count hits 0.
+ // Due to the unordered nature of tree pushes, once prepareTree
+ // is finished it is possible that the node was "resurrected" and has
+ // a non-zero parent count.
+ virtual void onMaybeRemovedFromTree(RenderNode* node) {}
+protected:
+ ~TreeObserver() {}
+};
+
// This would be a struct, but we want to PREVENT_COPY_AND_ASSIGN
class TreeInfo {
PREVENT_COPY_AND_ASSIGN(TreeInfo);
@@ -86,6 +98,10 @@
#endif
ErrorHandler* errorHandler = nullptr;
+ // Optional, may be nullptr. Used to allow things to observe interesting
+ // tree state changes
+ TreeObserver* observer = nullptr;
+
// Frame number for use with synchronized surfaceview position updating
int64_t frameNumber = -1;
int32_t windowInsetLeft = 0;
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index d35f764..adfe45c 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -17,6 +17,7 @@
#include "VectorDrawable.h"
#include "PathParser.h"
+#include "SkColorFilter.h"
#include "SkImageInfo.h"
#include "SkShader.h"
#include <utils/Log.h>
@@ -32,41 +33,36 @@
const int Tree::MAX_CACHED_BITMAP_SIZE = 2048;
-void Path::draw(SkCanvas* outCanvas, const SkMatrix& groupStackedMatrix, float scaleX, float scaleY) {
+void Path::draw(SkCanvas* outCanvas, const SkMatrix& groupStackedMatrix, float scaleX, float scaleY,
+ bool useStagingData) {
float matrixScale = getMatrixScale(groupStackedMatrix);
if (matrixScale == 0) {
// When either x or y is scaled to 0, we don't need to draw anything.
return;
}
- const SkPath updatedPath = getUpdatedPath();
SkMatrix pathMatrix(groupStackedMatrix);
pathMatrix.postScale(scaleX, scaleY);
//TODO: try apply the path matrix to the canvas instead of creating a new path.
SkPath renderPath;
renderPath.reset();
- renderPath.addPath(updatedPath, pathMatrix);
+
+ if (useStagingData) {
+ SkPath tmpPath;
+ getStagingPath(&tmpPath);
+ renderPath.addPath(tmpPath, pathMatrix);
+ } else {
+ renderPath.addPath(getUpdatedPath(), pathMatrix);
+ }
float minScale = fmin(scaleX, scaleY);
float strokeScale = minScale * matrixScale;
- drawPath(outCanvas, renderPath, strokeScale, pathMatrix);
-}
-
-void Path::setPathData(const Data& data) {
- if (mData == data) {
- return;
- }
- // Updates the path data. Note that we don't generate a new Skia path right away
- // because there are cases where the animation is changing the path data, but the view
- // that hosts the VD has gone off screen, in which case we won't even draw. So we
- // postpone the Skia path generation to the draw time.
- mData = data;
- mSkPathDirty = true;
+ drawPath(outCanvas, renderPath, strokeScale, pathMatrix, useStagingData);
}
void Path::dump() {
- ALOGD("Path: %s has %zu points", mName.c_str(), mData.points.size());
+ ALOGD("Path: %s has %zu points", mName.c_str(), mProperties.getData().points.size());
}
float Path::getMatrixScale(const SkMatrix& groupStackedMatrix) {
@@ -95,213 +91,215 @@
}
return matrixScale;
}
+
+// Called from UI thread during the initial setup/theme change.
Path::Path(const char* pathStr, size_t strLength) {
PathParser::ParseResult result;
- PathParser::getPathDataFromString(&mData, &result, pathStr, strLength);
- if (!result.failureOccurred) {
- VectorDrawableUtils::verbsToPath(&mSkPath, mData);
- }
-}
-
-Path::Path(const Data& data) {
- mData = data;
- // Now we need to construct a path
- VectorDrawableUtils::verbsToPath(&mSkPath, data);
+ Data data;
+ PathParser::getPathDataFromString(&data, &result, pathStr, strLength);
+ mStagingProperties.setData(data);
}
Path::Path(const Path& path) : Node(path) {
- mData = path.mData;
- VectorDrawableUtils::verbsToPath(&mSkPath, mData);
-}
-
-bool Path::canMorph(const Data& morphTo) {
- return VectorDrawableUtils::canMorph(mData, morphTo);
-}
-
-bool Path::canMorph(const Path& path) {
- return canMorph(path.mData);
+ mStagingProperties.syncProperties(path.mStagingProperties);
}
const SkPath& Path::getUpdatedPath() {
if (mSkPathDirty) {
mSkPath.reset();
- VectorDrawableUtils::verbsToPath(&mSkPath, mData);
+ VectorDrawableUtils::verbsToPath(&mSkPath, mProperties.getData());
mSkPathDirty = false;
}
return mSkPath;
}
-void Path::setPath(const char* pathStr, size_t strLength) {
- PathParser::ParseResult result;
- mSkPathDirty = true;
- PathParser::getPathDataFromString(&mData, &result, pathStr, strLength);
+void Path::getStagingPath(SkPath* outPath) {
+ outPath->reset();
+ VectorDrawableUtils::verbsToPath(outPath, mStagingProperties.getData());
+}
+
+void Path::syncProperties() {
+ if (mStagingPropertiesDirty) {
+ mProperties.syncProperties(mStagingProperties);
+ } else {
+ mStagingProperties.syncProperties(mProperties);
+ }
+ mStagingPropertiesDirty = false;
}
FullPath::FullPath(const FullPath& path) : Path(path) {
- mProperties = path.mProperties;
- SkRefCnt_SafeAssign(mStrokeGradient, path.mStrokeGradient);
- SkRefCnt_SafeAssign(mFillGradient, path.mFillGradient);
+ mStagingProperties.syncProperties(path.mStagingProperties);
+}
+
+static void applyTrim(SkPath* outPath, const SkPath& inPath, float trimPathStart, float trimPathEnd,
+ float trimPathOffset) {
+ if (trimPathStart == 0.0f && trimPathEnd == 1.0f) {
+ *outPath = inPath;
+ return;
+ }
+ outPath->reset();
+ if (trimPathStart == trimPathEnd) {
+ // Trimmed path should be empty.
+ return;
+ }
+ SkPathMeasure measure(inPath, false);
+ float len = SkScalarToFloat(measure.getLength());
+ float start = len * fmod((trimPathStart + trimPathOffset), 1.0f);
+ float end = len * fmod((trimPathEnd + trimPathOffset), 1.0f);
+
+ if (start > end) {
+ measure.getSegment(start, len, outPath, true);
+ if (end > 0) {
+ measure.getSegment(0, end, outPath, true);
+ }
+ } else {
+ measure.getSegment(start, end, outPath, true);
+ }
}
const SkPath& FullPath::getUpdatedPath() {
- if (!mSkPathDirty && !mTrimDirty) {
+ if (!mSkPathDirty && !mProperties.mTrimDirty) {
return mTrimmedSkPath;
}
Path::getUpdatedPath();
- if (mProperties.trimPathStart != 0.0f || mProperties.trimPathEnd != 1.0f) {
- applyTrim();
+ if (mProperties.getTrimPathStart() != 0.0f || mProperties.getTrimPathEnd() != 1.0f) {
+ mProperties.mTrimDirty = false;
+ applyTrim(&mTrimmedSkPath, mSkPath, mProperties.getTrimPathStart(),
+ mProperties.getTrimPathEnd(), mProperties.getTrimPathOffset());
return mTrimmedSkPath;
} else {
return mSkPath;
}
}
-void FullPath::updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha,
- SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd,
- float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin,
- int fillType) {
- mProperties.strokeWidth = strokeWidth;
- mProperties.strokeColor = strokeColor;
- mProperties.strokeAlpha = strokeAlpha;
- mProperties.fillColor = fillColor;
- mProperties.fillAlpha = fillAlpha;
- mProperties.strokeMiterLimit = strokeMiterLimit;
- mProperties.strokeLineCap = strokeLineCap;
- mProperties.strokeLineJoin = strokeLineJoin;
- mProperties.fillType = fillType;
-
- // If any trim property changes, mark trim dirty and update the trim path
- setTrimPathStart(trimPathStart);
- setTrimPathEnd(trimPathEnd);
- setTrimPathOffset(trimPathOffset);
+void FullPath::getStagingPath(SkPath* outPath) {
+ Path::getStagingPath(outPath);
+ SkPath inPath = *outPath;
+ applyTrim(outPath, inPath, mStagingProperties.getTrimPathStart(),
+ mStagingProperties.getTrimPathEnd(), mStagingProperties.getTrimPathOffset());
}
+void FullPath::dump() {
+ Path::dump();
+ ALOGD("stroke width, color, alpha: %f, %d, %f, fill color, alpha: %d, %f",
+ mProperties.getStrokeWidth(), mProperties.getStrokeColor(), mProperties.getStrokeAlpha(),
+ mProperties.getFillColor(), mProperties.getFillAlpha());
+}
+
+
inline SkColor applyAlpha(SkColor color, float alpha) {
int alphaBytes = SkColorGetA(color);
return SkColorSetA(color, alphaBytes * alpha);
}
void FullPath::drawPath(SkCanvas* outCanvas, SkPath& renderPath, float strokeScale,
- const SkMatrix& matrix){
+ const SkMatrix& matrix, bool useStagingData){
+ const FullPathProperties& properties = useStagingData ? mStagingProperties : mProperties;
+
// Draw path's fill, if fill color or gradient is valid
bool needsFill = false;
- if (mFillGradient != nullptr) {
- mPaint.setColor(applyAlpha(SK_ColorBLACK, mProperties.fillAlpha));
- SkShader* newShader = mFillGradient->newWithLocalMatrix(matrix);
- mPaint.setShader(newShader);
+ SkPaint paint;
+ if (properties.getFillGradient() != nullptr) {
+ paint.setColor(applyAlpha(SK_ColorBLACK, properties.getFillAlpha()));
+ SkShader* newShader = properties.getFillGradient()->newWithLocalMatrix(matrix);
+ paint.setShader(newShader);
needsFill = true;
- } else if (mProperties.fillColor != SK_ColorTRANSPARENT) {
- mPaint.setColor(applyAlpha(mProperties.fillColor, mProperties.fillAlpha));
+ } else if (properties.getFillColor() != SK_ColorTRANSPARENT) {
+ paint.setColor(applyAlpha(properties.getFillColor(), properties.getFillAlpha()));
needsFill = true;
}
if (needsFill) {
- mPaint.setStyle(SkPaint::Style::kFill_Style);
- mPaint.setAntiAlias(true);
- SkPath::FillType ft = static_cast<SkPath::FillType>(mProperties.fillType);
+ paint.setStyle(SkPaint::Style::kFill_Style);
+ paint.setAntiAlias(true);
+ SkPath::FillType ft = static_cast<SkPath::FillType>(properties.getFillType());
renderPath.setFillType(ft);
- outCanvas->drawPath(renderPath, mPaint);
+ outCanvas->drawPath(renderPath, paint);
}
- // Draw path's stroke, if stroke color or gradient is valid
+ // Draw path's stroke, if stroke color or Gradient is valid
bool needsStroke = false;
- if (mStrokeGradient != nullptr) {
- mPaint.setColor(applyAlpha(SK_ColorBLACK, mProperties.strokeAlpha));
- SkShader* newShader = mStrokeGradient->newWithLocalMatrix(matrix);
- mPaint.setShader(newShader);
+ if (properties.getStrokeGradient() != nullptr) {
+ paint.setColor(applyAlpha(SK_ColorBLACK, properties.getStrokeAlpha()));
+ SkShader* newShader = properties.getStrokeGradient()->newWithLocalMatrix(matrix);
+ paint.setShader(newShader);
needsStroke = true;
- } else if (mProperties.strokeColor != SK_ColorTRANSPARENT) {
- mPaint.setColor(applyAlpha(mProperties.strokeColor, mProperties.strokeAlpha));
+ } else if (properties.getStrokeColor() != SK_ColorTRANSPARENT) {
+ paint.setColor(applyAlpha(properties.getStrokeColor(), properties.getStrokeAlpha()));
needsStroke = true;
}
if (needsStroke) {
- mPaint.setStyle(SkPaint::Style::kStroke_Style);
- mPaint.setAntiAlias(true);
- mPaint.setStrokeJoin(SkPaint::Join(mProperties.strokeLineJoin));
- mPaint.setStrokeCap(SkPaint::Cap(mProperties.strokeLineCap));
- mPaint.setStrokeMiter(mProperties.strokeMiterLimit);
- mPaint.setStrokeWidth(mProperties.strokeWidth * strokeScale);
- outCanvas->drawPath(renderPath, mPaint);
+ paint.setStyle(SkPaint::Style::kStroke_Style);
+ paint.setAntiAlias(true);
+ paint.setStrokeJoin(SkPaint::Join(properties.getStrokeLineJoin()));
+ paint.setStrokeCap(SkPaint::Cap(properties.getStrokeLineCap()));
+ paint.setStrokeMiter(properties.getStrokeMiterLimit());
+ paint.setStrokeWidth(properties.getStrokeWidth() * strokeScale);
+ outCanvas->drawPath(renderPath, paint);
}
}
-/**
- * Applies trimming to the specified path.
- */
-void FullPath::applyTrim() {
- if (mProperties.trimPathStart == 0.0f && mProperties.trimPathEnd == 1.0f) {
- // No trimming necessary.
- return;
- }
- mTrimDirty = false;
- mTrimmedSkPath.reset();
- if (mProperties.trimPathStart == mProperties.trimPathEnd) {
- // Trimmed path should be empty.
- return;
- }
- SkPathMeasure measure(mSkPath, false);
- float len = SkScalarToFloat(measure.getLength());
- float start = len * fmod((mProperties.trimPathStart + mProperties.trimPathOffset), 1.0f);
- float end = len * fmod((mProperties.trimPathEnd + mProperties.trimPathOffset), 1.0f);
+void FullPath::syncProperties() {
+ Path::syncProperties();
- if (start > end) {
- measure.getSegment(start, len, &mTrimmedSkPath, true);
- if (end > 0) {
- measure.getSegment(0, end, &mTrimmedSkPath, true);
- }
+ if (mStagingPropertiesDirty) {
+ mProperties.syncProperties(mStagingProperties);
} else {
- measure.getSegment(start, end, &mTrimmedSkPath, true);
+ // Update staging property with property values from animation.
+ mStagingProperties.syncProperties(mProperties);
}
+ mStagingPropertiesDirty = false;
}
-REQUIRE_COMPATIBLE_LAYOUT(FullPath::Properties);
+REQUIRE_COMPATIBLE_LAYOUT(FullPath::FullPathProperties::PrimitiveFields);
static_assert(sizeof(float) == sizeof(int32_t), "float is not the same size as int32_t");
static_assert(sizeof(SkColor) == sizeof(int32_t), "SkColor is not the same size as int32_t");
-bool FullPath::getProperties(int8_t* outProperties, int length) {
- int propertyDataSize = sizeof(Properties);
+bool FullPath::FullPathProperties::copyProperties(int8_t* outProperties, int length) const {
+ int propertyDataSize = sizeof(FullPathProperties::PrimitiveFields);
if (length != propertyDataSize) {
LOG_ALWAYS_FATAL("Properties needs exactly %d bytes, a byte array of size %d is provided",
propertyDataSize, length);
return false;
}
- Properties* out = reinterpret_cast<Properties*>(outProperties);
- *out = mProperties;
+
+ PrimitiveFields* out = reinterpret_cast<PrimitiveFields*>(outProperties);
+ *out = mPrimitiveFields;
return true;
}
-void FullPath::setColorPropertyValue(int propertyId, int32_t value) {
+void FullPath::FullPathProperties::setColorPropertyValue(int propertyId, int32_t value) {
Property currentProperty = static_cast<Property>(propertyId);
- if (currentProperty == Property::StrokeColor) {
- mProperties.strokeColor = value;
- } else if (currentProperty == Property::FillColor) {
- mProperties.fillColor = value;
+ if (currentProperty == Property::strokeColor) {
+ setStrokeColor(value);
+ } else if (currentProperty == Property::fillColor) {
+ setFillColor(value);
} else {
- LOG_ALWAYS_FATAL("Error setting color property on FullPath: No valid property with id: %d",
- propertyId);
+ LOG_ALWAYS_FATAL("Error setting color property on FullPath: No valid property"
+ " with id: %d", propertyId);
}
}
-void FullPath::setPropertyValue(int propertyId, float value) {
+void FullPath::FullPathProperties::setPropertyValue(int propertyId, float value) {
Property property = static_cast<Property>(propertyId);
switch (property) {
- case Property::StrokeWidth:
+ case Property::strokeWidth:
setStrokeWidth(value);
break;
- case Property::StrokeAlpha:
+ case Property::strokeAlpha:
setStrokeAlpha(value);
break;
- case Property::FillAlpha:
+ case Property::fillAlpha:
setFillAlpha(value);
break;
- case Property::TrimPathStart:
+ case Property::trimPathStart:
setTrimPathStart(value);
break;
- case Property::TrimPathEnd:
+ case Property::trimPathEnd:
setTrimPathEnd(value);
break;
- case Property::TrimPathOffset:
+ case Property::trimPathOffset:
setTrimPathOffset(value);
break;
default:
@@ -311,16 +309,16 @@
}
void ClipPath::drawPath(SkCanvas* outCanvas, SkPath& renderPath,
- float strokeScale, const SkMatrix& matrix){
+ float strokeScale, const SkMatrix& matrix, bool useStagingData){
outCanvas->clipPath(renderPath, SkRegion::kIntersect_Op);
}
Group::Group(const Group& group) : Node(group) {
- mProperties = group.mProperties;
+ mStagingProperties.syncProperties(group.mStagingProperties);
}
void Group::draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix, float scaleX,
- float scaleY) {
+ float scaleY, bool useStagingData) {
// TODO: Try apply the matrix to the canvas instead of passing it down the tree
// Calculate current group's matrix by preConcat the parent's and
@@ -328,14 +326,15 @@
// Basically the Mfinal = Mviewport * M0 * M1 * M2;
// Mi the local matrix at level i of the group tree.
SkMatrix stackedMatrix;
- getLocalMatrix(&stackedMatrix);
+ const GroupProperties& prop = useStagingData ? mStagingProperties : mProperties;
+ getLocalMatrix(&stackedMatrix, prop);
stackedMatrix.postConcat(currentMatrix);
// Save the current clip information, which is local to this group.
outCanvas->save();
// Draw the group tree in the same order as the XML file.
for (auto& child : mChildren) {
- child->draw(outCanvas, stackedMatrix, scaleX, scaleY);
+ child->draw(outCanvas, stackedMatrix, scaleX, scaleY, useStagingData);
}
// Restore the previous clip information.
outCanvas->restore();
@@ -343,96 +342,106 @@
void Group::dump() {
ALOGD("Group %s has %zu children: ", mName.c_str(), mChildren.size());
+ ALOGD("Group translateX, Y : %f, %f, scaleX, Y: %f, %f", mProperties.getTranslateX(),
+ mProperties.getTranslateY(), mProperties.getScaleX(), mProperties.getScaleY());
for (size_t i = 0; i < mChildren.size(); i++) {
mChildren[i]->dump();
}
}
-void Group::updateLocalMatrix(float rotate, float pivotX, float pivotY,
- float scaleX, float scaleY, float translateX, float translateY) {
- setRotation(rotate);
- setPivotX(pivotX);
- setPivotY(pivotY);
- setScaleX(scaleX);
- setScaleY(scaleY);
- setTranslateX(translateX);
- setTranslateY(translateY);
+void Group::syncProperties() {
+ // Copy over the dirty staging properties
+ if (mStagingPropertiesDirty) {
+ mProperties.syncProperties(mStagingProperties);
+ } else {
+ mStagingProperties.syncProperties(mProperties);
+ }
+ mStagingPropertiesDirty = false;
+ for (auto& child : mChildren) {
+ child->syncProperties();
+ }
}
-void Group::getLocalMatrix(SkMatrix* outMatrix) {
+void Group::getLocalMatrix(SkMatrix* outMatrix, const GroupProperties& properties) {
outMatrix->reset();
// TODO: use rotate(mRotate, mPivotX, mPivotY) and scale with pivot point, instead of
// translating to pivot for rotating and scaling, then translating back.
- outMatrix->postTranslate(-mProperties.pivotX, -mProperties.pivotY);
- outMatrix->postScale(mProperties.scaleX, mProperties.scaleY);
- outMatrix->postRotate(mProperties.rotate, 0, 0);
- outMatrix->postTranslate(mProperties.translateX + mProperties.pivotX,
- mProperties.translateY + mProperties.pivotY);
+ outMatrix->postTranslate(-properties.getPivotX(), -properties.getPivotY());
+ outMatrix->postScale(properties.getScaleX(), properties.getScaleY());
+ outMatrix->postRotate(properties.getRotation(), 0, 0);
+ outMatrix->postTranslate(properties.getTranslateX() + properties.getPivotX(),
+ properties.getTranslateY() + properties.getPivotY());
}
void Group::addChild(Node* child) {
mChildren.emplace_back(child);
+ if (mPropertyChangedListener != nullptr) {
+ child->setPropertyChangedListener(mPropertyChangedListener);
+ }
}
-bool Group::getProperties(float* outProperties, int length) {
- int propertyCount = static_cast<int>(Property::Count);
+bool Group::GroupProperties::copyProperties(float* outProperties, int length) const {
+ int propertyCount = static_cast<int>(Property::count);
if (length != propertyCount) {
LOG_ALWAYS_FATAL("Properties needs exactly %d bytes, a byte array of size %d is provided",
propertyCount, length);
return false;
}
- Properties* out = reinterpret_cast<Properties*>(outProperties);
- *out = mProperties;
+
+ PrimitiveFields* out = reinterpret_cast<PrimitiveFields*>(outProperties);
+ *out = mPrimitiveFields;
return true;
}
// TODO: Consider animating the properties as float pointers
-float Group::getPropertyValue(int propertyId) const {
+// Called on render thread
+float Group::GroupProperties::getPropertyValue(int propertyId) const {
Property currentProperty = static_cast<Property>(propertyId);
switch (currentProperty) {
- case Property::Rotate:
- return mProperties.rotate;
- case Property::PivotX:
- return mProperties.pivotX;
- case Property::PivotY:
- return mProperties.pivotY;
- case Property::ScaleX:
- return mProperties.scaleX;
- case Property::ScaleY:
- return mProperties.scaleY;
- case Property::TranslateX:
- return mProperties.translateX;
- case Property::TranslateY:
- return mProperties.translateY;
+ case Property::rotate:
+ return getRotation();
+ case Property::pivotX:
+ return getPivotX();
+ case Property::pivotY:
+ return getPivotY();
+ case Property::scaleX:
+ return getScaleX();
+ case Property::scaleY:
+ return getScaleY();
+ case Property::translateX:
+ return getTranslateX();
+ case Property::translateY:
+ return getTranslateY();
default:
LOG_ALWAYS_FATAL("Invalid property index: %d", propertyId);
return 0;
}
}
-void Group::setPropertyValue(int propertyId, float value) {
+// Called on render thread
+void Group::GroupProperties::setPropertyValue(int propertyId, float value) {
Property currentProperty = static_cast<Property>(propertyId);
switch (currentProperty) {
- case Property::Rotate:
- mProperties.rotate = value;
+ case Property::rotate:
+ setRotation(value);
break;
- case Property::PivotX:
- mProperties.pivotX = value;
+ case Property::pivotX:
+ setPivotX(value);
break;
- case Property::PivotY:
- mProperties.pivotY = value;
+ case Property::pivotY:
+ setPivotY(value);
break;
- case Property::ScaleX:
- mProperties.scaleX = value;
+ case Property::scaleX:
+ setScaleX(value);
break;
- case Property::ScaleY:
- mProperties.scaleY = value;
+ case Property::scaleY:
+ setScaleY(value);
break;
- case Property::TranslateX:
- mProperties.translateX = value;
+ case Property::translateX:
+ setTranslateX(value);
break;
- case Property::TranslateY:
- mProperties.translateY = value;
+ case Property::translateY:
+ setTranslateY(value);
break;
default:
LOG_ALWAYS_FATAL("Invalid property index: %d", propertyId);
@@ -440,7 +449,11 @@
}
bool Group::isValidProperty(int propertyId) {
- return propertyId >= 0 && propertyId < static_cast<int>(Property::Count);
+ return GroupProperties::isValidProperty(propertyId);
+}
+
+bool Group::GroupProperties::isValidProperty(int propertyId) {
+ return propertyId >= 0 && propertyId < static_cast<int>(Property::count);
}
void Tree::draw(Canvas* outCanvas, SkColorFilter* colorFilter,
@@ -449,18 +462,18 @@
// avoid blurry scaling, we have to draw into a bitmap with exact pixel
// size first. This bitmap size is determined by the bounds and the
// canvas scale.
- outCanvas->getMatrix(&mCanvasMatrix);
- mBounds = bounds;
+ SkMatrix canvasMatrix;
+ outCanvas->getMatrix(&canvasMatrix);
float canvasScaleX = 1.0f;
float canvasScaleY = 1.0f;
- if (mCanvasMatrix.getSkewX() == 0 && mCanvasMatrix.getSkewY() == 0) {
+ if (canvasMatrix.getSkewX() == 0 && canvasMatrix.getSkewY() == 0) {
// Only use the scale value when there's no skew or rotation in the canvas matrix.
// TODO: Add a cts test for drawing VD on a canvas with negative scaling factors.
- canvasScaleX = fabs(mCanvasMatrix.getScaleX());
- canvasScaleY = fabs(mCanvasMatrix.getScaleY());
+ canvasScaleX = fabs(canvasMatrix.getScaleX());
+ canvasScaleY = fabs(canvasMatrix.getScaleY());
}
- int scaledWidth = (int) (mBounds.width() * canvasScaleX);
- int scaledHeight = (int) (mBounds.height() * canvasScaleY);
+ int scaledWidth = (int) (bounds.width() * canvasScaleX);
+ int scaledHeight = (int) (bounds.height() * canvasScaleY);
scaledWidth = std::min(Tree::MAX_CACHED_BITMAP_SIZE, scaledWidth);
scaledHeight = std::min(Tree::MAX_CACHED_BITMAP_SIZE, scaledHeight);
@@ -468,63 +481,105 @@
return;
}
- mPaint.setColorFilter(colorFilter);
-
+ mStagingProperties.setScaledSize(scaledWidth, scaledHeight);
int saveCount = outCanvas->save(SaveFlags::MatrixClip);
- outCanvas->translate(mBounds.fLeft, mBounds.fTop);
+ outCanvas->translate(bounds.fLeft, bounds.fTop);
// Handle RTL mirroring.
if (needsMirroring) {
- outCanvas->translate(mBounds.width(), 0);
+ outCanvas->translate(bounds.width(), 0);
outCanvas->scale(-1.0f, 1.0f);
}
+ mStagingProperties.setColorFilter(colorFilter);
// At this point, canvas has been translated to the right position.
// And we use this bound for the destination rect for the drawBitmap, so
// we offset to (0, 0);
- mBounds.offsetTo(0, 0);
- createCachedBitmapIfNeeded(scaledWidth, scaledHeight);
-
+ SkRect tmpBounds = bounds;
+ tmpBounds.offsetTo(0, 0);
+ mStagingProperties.setBounds(tmpBounds);
outCanvas->drawVectorDrawable(this);
-
outCanvas->restoreToCount(saveCount);
}
-SkPaint* Tree::getPaint() {
- SkPaint* paint;
- if (mRootAlpha == 1.0f && mPaint.getColorFilter() == NULL) {
- paint = NULL;
- } else {
- mPaint.setFilterQuality(kLow_SkFilterQuality);
- mPaint.setAlpha(mRootAlpha * 255);
- paint = &mPaint;
+void Tree::drawStaging(Canvas* outCanvas) {
+ bool redrawNeeded = allocateBitmapIfNeeded(&mStagingCache.bitmap,
+ mStagingProperties.getScaledWidth(), mStagingProperties.getScaledHeight());
+ // draw bitmap cache
+ if (redrawNeeded || mStagingCache.dirty) {
+ updateBitmapCache(&mStagingCache.bitmap, true);
+ mStagingCache.dirty = false;
}
- return paint;
+
+ SkPaint tmpPaint;
+ SkPaint* paint = updatePaint(&tmpPaint, &mStagingProperties);
+ outCanvas->drawBitmap(mStagingCache.bitmap, 0, 0,
+ mStagingCache.bitmap.width(), mStagingCache.bitmap.height(),
+ mStagingProperties.getBounds().left(), mStagingProperties.getBounds().top(),
+ mStagingProperties.getBounds().right(), mStagingProperties.getBounds().bottom(), paint);
+}
+
+SkPaint* Tree::getPaint() {
+ return updatePaint(&mPaint, &mProperties);
+}
+
+// Update the given paint with alpha and color filter. Return nullptr if no color filter is
+// specified and root alpha is 1. Otherwise, return updated paint.
+SkPaint* Tree::updatePaint(SkPaint* outPaint, TreeProperties* prop) {
+ if (prop->getRootAlpha() == 1.0f && prop->getColorFilter() == nullptr) {
+ return nullptr;
+ } else {
+ outPaint->setColorFilter(mStagingProperties.getColorFilter());
+ outPaint->setFilterQuality(kLow_SkFilterQuality);
+ outPaint->setAlpha(prop->getRootAlpha() * 255);
+ return outPaint;
+ }
}
const SkBitmap& Tree::getBitmapUpdateIfDirty() {
- mCachedBitmap.eraseColor(SK_ColorTRANSPARENT);
- SkCanvas outCanvas(mCachedBitmap);
- float scaleX = (float) mCachedBitmap.width() / mViewportWidth;
- float scaleY = (float) mCachedBitmap.height() / mViewportHeight;
- mRootNode->draw(&outCanvas, SkMatrix::I(), scaleX, scaleY);
- mCacheDirty = false;
- return mCachedBitmap;
+ bool redrawNeeded = allocateBitmapIfNeeded(&mCache.bitmap, mProperties.getScaledWidth(),
+ mProperties.getScaledHeight());
+ if (redrawNeeded || mCache.dirty) {
+ updateBitmapCache(&mCache.bitmap, false);
+ mCache.dirty = false;
+ }
+ return mCache.bitmap;
}
-void Tree::createCachedBitmapIfNeeded(int width, int height) {
- if (!canReuseBitmap(width, height)) {
+void Tree::updateBitmapCache(SkBitmap* outCache, bool useStagingData) {
+ outCache->eraseColor(SK_ColorTRANSPARENT);
+ SkCanvas outCanvas(*outCache);
+ float viewportWidth = useStagingData ?
+ mStagingProperties.getViewportWidth() : mProperties.getViewportWidth();
+ float viewportHeight = useStagingData ?
+ mStagingProperties.getViewportHeight() : mProperties.getViewportHeight();
+ float scaleX = outCache->width() / viewportWidth;
+ float scaleY = outCache->height() / viewportHeight;
+ mRootNode->draw(&outCanvas, SkMatrix::I(), scaleX, scaleY, useStagingData);
+}
+
+bool Tree::allocateBitmapIfNeeded(SkBitmap* outCache, int width, int height) {
+ if (!canReuseBitmap(*outCache, width, height)) {
SkImageInfo info = SkImageInfo::Make(width, height,
kN32_SkColorType, kPremul_SkAlphaType);
- mCachedBitmap.setInfo(info);
+ outCache->setInfo(info);
// TODO: Count the bitmap cache against app's java heap
- mCachedBitmap.allocPixels(info);
- mCacheDirty = true;
+ outCache->allocPixels(info);
+ return true;
}
+ return false;
}
-bool Tree::canReuseBitmap(int width, int height) {
- return width == mCachedBitmap.width() && height == mCachedBitmap.height();
+bool Tree::canReuseBitmap(const SkBitmap& bitmap, int width, int height) {
+ return width == bitmap.width() && height == bitmap.height();
+}
+
+void Tree::onPropertyChanged(TreeProperties* prop) {
+ if (prop == &mStagingProperties) {
+ mStagingCache.dirty = true;
+ } else {
+ mCache.dirty = true;
+ }
}
}; // namespace VectorDrawable
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index 7a45bf5..e4c7ed7 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -18,9 +18,11 @@
#define ANDROID_HWUI_VPATH_H
#include "hwui/Canvas.h"
+#include "DisplayList.h"
#include <SkBitmap.h>
#include <SkColor.h>
+#include <SkColorFilter.h>
#include <SkCanvas.h>
#include <SkMatrix.h>
#include <SkPaint.h>
@@ -38,8 +40,11 @@
namespace uirenderer {
namespace VectorDrawable {
-#define VD_SET_PROP_WITH_FLAG(field, value, flag) (VD_SET_PROP(field, value) ? (flag = true, true): false);
+#define VD_SET_PROP_WITH_FLAG(field, value, flag) (VD_SET_PROP_AND_NOTIFY(field, value) ? (flag = true, true) : false)
#define VD_SET_PROP(field, value) (value != field ? (field = value, true) : false)
+#define VD_SET_PROP_AND_NOTIFY(field, value) ({ bool retVal = VD_SET_PROP(field, value);\
+ onPropertyChanged(); retVal;})
+#define UPDATE_SKPROP(field, value) ({bool retVal = (field != value); if (field != value) SkRefCnt_SafeAssign(field, value); retVal;})
/* A VectorDrawable is composed of a tree of nodes.
* Each node can be a group node, or a path.
@@ -52,22 +57,65 @@
* / \ |
* Path Path Path
*
+ * VectorDrawables are drawn into bitmap caches first, then the caches are drawn to the given
+ * canvas with root alpha applied. Two caches are maintained for VD, one in UI thread, the other in
+ * Render Thread. A generation id is used to keep track of changes in the vector drawable tree.
+ * Each cache has their own generation id to track whether they are up to date with the latest
+ * change in the tree.
+ *
+ * Any property change to the vector drawable coming from UI thread (such as bulk setters to update
+ * all the properties, and viewport change, etc.) are only modifying the staging properties. The
+ * staging properties will then be marked dirty and will be pushed over to render thread properties
+ * at sync point. If staging properties are not dirty at sync point, we sync backwards by updating
+ * staging properties with render thread properties to reflect the latest animation value.
+ *
*/
+
+class PropertyChangedListener {
+public:
+ PropertyChangedListener(bool* dirty, bool* stagingDirty)
+ : mDirty(dirty), mStagingDirty(stagingDirty) {}
+ void onPropertyChanged() {
+ *mDirty = true;
+ }
+ void onStagingPropertyChanged() {
+ *mStagingDirty = true;
+ }
+private:
+ bool* mDirty;
+ bool* mStagingDirty;
+};
+
class ANDROID_API Node {
public:
+ class Properties {
+ public:
+ Properties(Node* node) : mNode(node) {}
+ inline void onPropertyChanged() {
+ mNode->onPropertyChanged(this);
+ }
+ private:
+ Node* mNode;
+ };
Node(const Node& node) {
mName = node.mName;
}
Node() {}
virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
- float scaleX, float scaleY) = 0;
+ float scaleX, float scaleY, bool useStagingData) = 0;
virtual void dump() = 0;
void setName(const char* name) {
mName = name;
}
+ virtual void setPropertyChangedListener(PropertyChangedListener* listener) {
+ mPropertyChangedListener = listener;
+ }
+ virtual void onPropertyChanged(Properties* properties) = 0;
virtual ~Node(){}
+ virtual void syncProperties() = 0;
protected:
std::string mName;
+ PropertyChangedListener* mPropertyChangedListener = nullptr;
};
class ANDROID_API Path : public Node {
@@ -81,150 +129,267 @@
&& points == data.points;
}
};
- Path(const Data& nodes);
+
+ class PathProperties : public Properties {
+ public:
+ PathProperties(Node* node) : Properties(node) {}
+ void syncProperties(const PathProperties& prop) {
+ mData = prop.mData;
+ onPropertyChanged();
+ }
+ void setData(const Data& data) {
+ // Updates the path data. Note that we don't generate a new Skia path right away
+ // because there are cases where the animation is changing the path data, but the view
+ // that hosts the VD has gone off screen, in which case we won't even draw. So we
+ // postpone the Skia path generation to the draw time.
+ if (data == mData) {
+ return;
+ }
+ mData = data;
+ onPropertyChanged();
+
+ }
+ const Data& getData() const {
+ return mData;
+ }
+ private:
+ Data mData;
+ };
+
Path(const Path& path);
Path(const char* path, size_t strLength);
Path() {}
+
void dump() override;
- bool canMorph(const Data& path);
- bool canMorph(const Path& path);
void draw(SkCanvas* outCanvas, const SkMatrix& groupStackedMatrix,
- float scaleX, float scaleY) override;
- void setPath(const char* path, size_t strLength);
- void setPathData(const Data& data);
+ float scaleX, float scaleY, bool useStagingData) override;
static float getMatrixScale(const SkMatrix& groupStackedMatrix);
+ virtual void syncProperties() override;
+ virtual void onPropertyChanged(Properties* prop) override {
+ if (prop == &mStagingProperties) {
+ mStagingPropertiesDirty = true;
+ if (mPropertyChangedListener) {
+ mPropertyChangedListener->onStagingPropertyChanged();
+ }
+ } else if (prop == &mProperties){
+ mSkPathDirty = true;
+ if (mPropertyChangedListener) {
+ mPropertyChangedListener->onPropertyChanged();
+ }
+ }
+ }
+ PathProperties* mutateStagingProperties() { return &mStagingProperties; }
+ const PathProperties* stagingProperties() { return &mStagingProperties; }
+
+ // This should only be called from animations on RT
+ PathProperties* mutateProperties() { return &mProperties; }
protected:
virtual const SkPath& getUpdatedPath();
+ virtual void getStagingPath(SkPath* outPath);
virtual void drawPath(SkCanvas *outCanvas, SkPath& renderPath,
- float strokeScale, const SkMatrix& matrix) = 0;
- Data mData;
- SkPath mSkPath;
+ float strokeScale, const SkMatrix& matrix, bool useStagingData) = 0;
+
+ // Internal data, render thread only.
bool mSkPathDirty = true;
+ SkPath mSkPath;
+
+private:
+ PathProperties mProperties = PathProperties(this);
+ PathProperties mStagingProperties = PathProperties(this);
+ bool mStagingPropertiesDirty = true;
};
class ANDROID_API FullPath: public Path {
public:
+ class FullPathProperties : public Properties {
+ public:
+ struct PrimitiveFields {
+ float strokeWidth = 0;
+ SkColor strokeColor = SK_ColorTRANSPARENT;
+ float strokeAlpha = 1;
+ SkColor fillColor = SK_ColorTRANSPARENT;
+ float fillAlpha = 1;
+ float trimPathStart = 0;
+ float trimPathEnd = 1;
+ float trimPathOffset = 0;
+ int32_t strokeLineCap = SkPaint::Cap::kButt_Cap;
+ int32_t strokeLineJoin = SkPaint::Join::kMiter_Join;
+ float strokeMiterLimit = 4;
+ int fillType = 0; /* non-zero or kWinding_FillType in Skia */
+ };
+ FullPathProperties(Node* mNode) : Properties(mNode), mTrimDirty(false) {}
+ void syncProperties(const FullPathProperties& prop) {
+ mPrimitiveFields = prop.mPrimitiveFields;
+ mTrimDirty = true;
+ fillGradient.reset(prop.fillGradient);
+ strokeGradient.reset(prop.strokeGradient);
+ onPropertyChanged();
+ }
+ void setFillGradient(SkShader* gradient) {
+ if(fillGradient != gradient){
+ fillGradient.reset(gradient);
+ onPropertyChanged();
+ }
+ }
+ void setStrokeGradient(SkShader* gradient) {
+ if(strokeGradient != gradient){
+ strokeGradient.reset(gradient);
+ onPropertyChanged();
+ }
+ }
+ SkShader* getFillGradient() const {
+ return fillGradient;
+ }
+ SkShader* getStrokeGradient() const {
+ return strokeGradient;
+ }
+ float getStrokeWidth() const{
+ return mPrimitiveFields.strokeWidth;
+ }
+ void setStrokeWidth(float strokeWidth) {
+ VD_SET_PROP_AND_NOTIFY(strokeWidth, strokeWidth);
+ }
+ SkColor getStrokeColor() const{
+ return mPrimitiveFields.strokeColor;
+ }
+ void setStrokeColor(SkColor strokeColor) {
+ VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.strokeColor, strokeColor);
+ }
+ float getStrokeAlpha() const{
+ return mPrimitiveFields.strokeAlpha;
+ }
+ void setStrokeAlpha(float strokeAlpha) {
+ VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.strokeAlpha, strokeAlpha);
+ }
+ SkColor getFillColor() const {
+ return mPrimitiveFields.fillColor;
+ }
+ void setFillColor(SkColor fillColor) {
+ VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.fillColor, fillColor);
+ }
+ float getFillAlpha() const{
+ return mPrimitiveFields.fillAlpha;
+ }
+ void setFillAlpha(float fillAlpha) {
+ VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.fillAlpha, fillAlpha);
+ }
+ float getTrimPathStart() const{
+ return mPrimitiveFields.trimPathStart;
+ }
+ void setTrimPathStart(float trimPathStart) {
+ VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathStart, trimPathStart, mTrimDirty);
+ }
+ float getTrimPathEnd() const{
+ return mPrimitiveFields.trimPathEnd;
+ }
+ void setTrimPathEnd(float trimPathEnd) {
+ VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathEnd, trimPathEnd, mTrimDirty);
+ }
+ float getTrimPathOffset() const{
+ return mPrimitiveFields.trimPathOffset;
+ }
+ void setTrimPathOffset(float trimPathOffset) {
+ VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathOffset, trimPathOffset, mTrimDirty);
+ }
-struct Properties {
- float strokeWidth = 0;
- SkColor strokeColor = SK_ColorTRANSPARENT;
- float strokeAlpha = 1;
- SkColor fillColor = SK_ColorTRANSPARENT;
- float fillAlpha = 1;
- float trimPathStart = 0;
- float trimPathEnd = 1;
- float trimPathOffset = 0;
- int32_t strokeLineCap = SkPaint::Cap::kButt_Cap;
- int32_t strokeLineJoin = SkPaint::Join::kMiter_Join;
- float strokeMiterLimit = 4;
- int fillType = 0; /* non-zero or kWinding_FillType in Skia */
-};
+ float getStrokeMiterLimit() const {
+ return mPrimitiveFields.strokeMiterLimit;
+ }
+ float getStrokeLineCap() const {
+ return mPrimitiveFields.strokeLineCap;
+ }
+ float getStrokeLineJoin() const {
+ return mPrimitiveFields.strokeLineJoin;
+ }
+ float getFillType() const {
+ return mPrimitiveFields.fillType;
+ }
+ bool copyProperties(int8_t* outProperties, int length) const;
+ void updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha,
+ SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd,
+ float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin,
+ int fillType) {
+ mPrimitiveFields.strokeWidth = strokeWidth;
+ mPrimitiveFields.strokeColor = strokeColor;
+ mPrimitiveFields.strokeAlpha = strokeAlpha;
+ mPrimitiveFields.fillColor = fillColor;
+ mPrimitiveFields.fillAlpha = fillAlpha;
+ mPrimitiveFields.trimPathStart = trimPathStart;
+ mPrimitiveFields.trimPathEnd = trimPathEnd;
+ mPrimitiveFields.trimPathOffset = trimPathOffset;
+ mPrimitiveFields.strokeMiterLimit = strokeMiterLimit;
+ mPrimitiveFields.strokeLineCap = strokeLineCap;
+ mPrimitiveFields.strokeLineJoin = strokeLineJoin;
+ mPrimitiveFields.fillType = fillType;
+ mTrimDirty = true;
+ onPropertyChanged();
+ }
+ // Set property values during animation
+ void setColorPropertyValue(int propertyId, int32_t value);
+ void setPropertyValue(int propertyId, float value);
+ bool mTrimDirty;
+ private:
+ enum class Property {
+ strokeWidth = 0,
+ strokeColor,
+ strokeAlpha,
+ fillColor,
+ fillAlpha,
+ trimPathStart,
+ trimPathEnd,
+ trimPathOffset,
+ strokeLineCap,
+ strokeLineJoin,
+ strokeMiterLimit,
+ fillType,
+ count,
+ };
+ PrimitiveFields mPrimitiveFields;
+ SkAutoTUnref<SkShader> fillGradient;
+ SkAutoTUnref<SkShader> strokeGradient;
+ };
+ // Called from UI thread
FullPath(const FullPath& path); // for cloning
FullPath(const char* path, size_t strLength) : Path(path, strLength) {}
FullPath() : Path() {}
- FullPath(const Data& nodes) : Path(nodes) {}
+ void dump() override;
+ FullPathProperties* mutateStagingProperties() { return &mStagingProperties; }
+ const FullPathProperties* stagingProperties() { return &mStagingProperties; }
- ~FullPath() {
- SkSafeUnref(mFillGradient);
- SkSafeUnref(mStrokeGradient);
- }
+ // This should only be called from animations on RT
+ FullPathProperties* mutateProperties() { return &mProperties; }
- void updateProperties(float strokeWidth, SkColor strokeColor,
- float strokeAlpha, SkColor fillColor, float fillAlpha,
- float trimPathStart, float trimPathEnd, float trimPathOffset,
- float strokeMiterLimit, int strokeLineCap, int strokeLineJoin, int fillType);
- // TODO: Cleanup: Remove the setter and getters below, and their counterparts in java and JNI
- float getStrokeWidth() {
- return mProperties.strokeWidth;
+ virtual void syncProperties() override;
+ virtual void onPropertyChanged(Properties* properties) override {
+ Path::onPropertyChanged(properties);
+ if (properties == &mStagingProperties) {
+ mStagingPropertiesDirty = true;
+ if (mPropertyChangedListener) {
+ mPropertyChangedListener->onStagingPropertyChanged();
+ }
+ } else if (properties == &mProperties) {
+ if (mPropertyChangedListener) {
+ mPropertyChangedListener->onPropertyChanged();
+ }
+ }
}
- void setStrokeWidth(float strokeWidth) {
- mProperties.strokeWidth = strokeWidth;
- }
- SkColor getStrokeColor() {
- return mProperties.strokeColor;
- }
- void setStrokeColor(SkColor strokeColor) {
- mProperties.strokeColor = strokeColor;
- }
- float getStrokeAlpha() {
- return mProperties.strokeAlpha;
- }
- void setStrokeAlpha(float strokeAlpha) {
- mProperties.strokeAlpha = strokeAlpha;
- }
- SkColor getFillColor() {
- return mProperties.fillColor;
- }
- void setFillColor(SkColor fillColor) {
- mProperties.fillColor = fillColor;
- }
- float getFillAlpha() {
- return mProperties.fillAlpha;
- }
- void setFillAlpha(float fillAlpha) {
- mProperties.fillAlpha = fillAlpha;
- }
- float getTrimPathStart() {
- return mProperties.trimPathStart;
- }
- void setTrimPathStart(float trimPathStart) {
- VD_SET_PROP_WITH_FLAG(mProperties.trimPathStart, trimPathStart, mTrimDirty);
- }
- float getTrimPathEnd() {
- return mProperties.trimPathEnd;
- }
- void setTrimPathEnd(float trimPathEnd) {
- VD_SET_PROP_WITH_FLAG(mProperties.trimPathEnd, trimPathEnd, mTrimDirty);
- }
- float getTrimPathOffset() {
- return mProperties.trimPathOffset;
- }
- void setTrimPathOffset(float trimPathOffset) {
- VD_SET_PROP_WITH_FLAG(mProperties.trimPathOffset, trimPathOffset, mTrimDirty);
- }
- bool getProperties(int8_t* outProperties, int length);
- void setColorPropertyValue(int propertyId, int32_t value);
- void setPropertyValue(int propertyId, float value);
-
- void setFillGradient(SkShader* fillGradient) {
- SkRefCnt_SafeAssign(mFillGradient, fillGradient);
- };
- void setStrokeGradient(SkShader* strokeGradient) {
- SkRefCnt_SafeAssign(mStrokeGradient, strokeGradient);
- };
-
protected:
const SkPath& getUpdatedPath() override;
+ void getStagingPath(SkPath* outPath) override;
void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
- float strokeScale, const SkMatrix& matrix) override;
-
+ float strokeScale, const SkMatrix& matrix, bool useStagingData) override;
private:
- enum class Property {
- StrokeWidth = 0,
- StrokeColor,
- StrokeAlpha,
- FillColor,
- FillAlpha,
- TrimPathStart,
- TrimPathEnd,
- TrimPathOffset,
- StrokeLineCap,
- StrokeLineJoin,
- StrokeMiterLimit,
- FillType,
- Count,
- };
- // Applies trimming to the specified path.
- void applyTrim();
- Properties mProperties;
- bool mTrimDirty = true;
+
+ FullPathProperties mProperties = FullPathProperties(this);
+ FullPathProperties mStagingProperties = FullPathProperties(this);
+ bool mStagingPropertiesDirty = true;
+
+ // Intermediate data for drawing, render thread only
SkPath mTrimmedSkPath;
- SkPaint mPaint;
- SkShader* mStrokeGradient = nullptr;
- SkShader* mFillGradient = nullptr;
+
};
class ANDROID_API ClipPath: public Path {
@@ -232,143 +397,316 @@
ClipPath(const ClipPath& path) : Path(path) {}
ClipPath(const char* path, size_t strLength) : Path(path, strLength) {}
ClipPath() : Path() {}
- ClipPath(const Data& nodes) : Path(nodes) {}
protected:
void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
- float strokeScale, const SkMatrix& matrix) override;
+ float strokeScale, const SkMatrix& matrix, bool useStagingData) override;
};
class ANDROID_API Group: public Node {
public:
- struct Properties {
- float rotate = 0;
- float pivotX = 0;
- float pivotY = 0;
- float scaleX = 1;
- float scaleY = 1;
- float translateX = 0;
- float translateY = 0;
+ class GroupProperties : public Properties {
+ public:
+ GroupProperties(Node* mNode) : Properties(mNode) {}
+ struct PrimitiveFields {
+ float rotate = 0;
+ float pivotX = 0;
+ float pivotY = 0;
+ float scaleX = 1;
+ float scaleY = 1;
+ float translateX = 0;
+ float translateY = 0;
+ } mPrimitiveFields;
+ void syncProperties(const GroupProperties& prop) {
+ mPrimitiveFields = prop.mPrimitiveFields;
+ onPropertyChanged();
+ }
+ float getRotation() const {
+ return mPrimitiveFields.rotate;
+ }
+ void setRotation(float rotation) {
+ VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.rotate, rotation);
+ }
+ float getPivotX() const {
+ return mPrimitiveFields.pivotX;
+ }
+ void setPivotX(float pivotX) {
+ VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.pivotX, pivotX);
+ }
+ float getPivotY() const {
+ return mPrimitiveFields.pivotY;
+ }
+ void setPivotY(float pivotY) {
+ VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.pivotY, pivotY);
+ }
+ float getScaleX() const {
+ return mPrimitiveFields.scaleX;
+ }
+ void setScaleX(float scaleX) {
+ VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.scaleX, scaleX);
+ }
+ float getScaleY() const {
+ return mPrimitiveFields.scaleY;
+ }
+ void setScaleY(float scaleY) {
+ VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.scaleY, scaleY);
+ }
+ float getTranslateX() const {
+ return mPrimitiveFields.translateX;
+ }
+ void setTranslateX(float translateX) {
+ VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.translateX, translateX);
+ }
+ float getTranslateY() const {
+ return mPrimitiveFields.translateY;
+ }
+ void setTranslateY(float translateY) {
+ VD_SET_PROP_AND_NOTIFY(translateY, translateY);
+ }
+ void updateProperties(float rotate, float pivotX, float pivotY,
+ float scaleX, float scaleY, float translateX, float translateY) {
+ mPrimitiveFields.rotate = rotate;
+ mPrimitiveFields.pivotX = pivotX;
+ mPrimitiveFields.pivotY = pivotY;
+ mPrimitiveFields.scaleX = scaleX;
+ mPrimitiveFields.scaleY = scaleY;
+ mPrimitiveFields.translateX = translateX;
+ mPrimitiveFields.translateY = translateY;
+ onPropertyChanged();
+ }
+ void setPropertyValue(int propertyId, float value);
+ float getPropertyValue(int propertyId) const;
+ bool copyProperties(float* outProperties, int length) const;
+ static bool isValidProperty(int propertyId);
+ private:
+ enum class Property {
+ rotate = 0,
+ pivotX,
+ pivotY,
+ scaleX,
+ scaleY,
+ translateX,
+ translateY,
+ // Count of the properties, must be at the end.
+ count,
+ };
};
+
Group(const Group& group);
Group() {}
- float getRotation() {
- return mProperties.rotate;
- }
- void setRotation(float rotation) {
- mProperties.rotate = rotation;
- }
- float getPivotX() {
- return mProperties.pivotX;
- }
- void setPivotX(float pivotX) {
- mProperties.pivotX = pivotX;
- }
- float getPivotY() {
- return mProperties.pivotY;
- }
- void setPivotY(float pivotY) {
- mProperties.pivotY = pivotY;
- }
- float getScaleX() {
- return mProperties.scaleX;
- }
- void setScaleX(float scaleX) {
- mProperties.scaleX = scaleX;
- }
- float getScaleY() {
- return mProperties.scaleY;
- }
- void setScaleY(float scaleY) {
- mProperties.scaleY = scaleY;
- }
- float getTranslateX() {
- return mProperties.translateX;
- }
- void setTranslateX(float translateX) {
- mProperties.translateX = translateX;
- }
- float getTranslateY() {
- return mProperties.translateY;
- }
- void setTranslateY(float translateY) {
- mProperties.translateY = translateY;
- }
- virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
- float scaleX, float scaleY) override;
- void updateLocalMatrix(float rotate, float pivotX, float pivotY,
- float scaleX, float scaleY, float translateX, float translateY);
- void getLocalMatrix(SkMatrix* outMatrix);
void addChild(Node* child);
+ virtual void setPropertyChangedListener(PropertyChangedListener* listener) override {
+ Node::setPropertyChangedListener(listener);
+ for (auto& child : mChildren) {
+ child->setPropertyChangedListener(listener);
+ }
+ }
+ virtual void syncProperties() override;
+ GroupProperties* mutateStagingProperties() { return &mStagingProperties; }
+ const GroupProperties* stagingProperties() { return &mStagingProperties; }
+
+ // This should only be called from animations on RT
+ GroupProperties* mutateProperties() { return &mProperties; }
+
+ // Methods below could be called from either UI thread or Render Thread.
+ virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
+ float scaleX, float scaleY, bool useStagingData) override;
+ void getLocalMatrix(SkMatrix* outMatrix, const GroupProperties& properties);
void dump() override;
- bool getProperties(float* outProperties, int length);
- float getPropertyValue(int propertyId) const;
- void setPropertyValue(int propertyId, float value);
static bool isValidProperty(int propertyId);
+ virtual void onPropertyChanged(Properties* properties) override {
+ if (properties == &mStagingProperties) {
+ mStagingPropertiesDirty = true;
+ if (mPropertyChangedListener) {
+ mPropertyChangedListener->onStagingPropertyChanged();
+ }
+ } else {
+ if (mPropertyChangedListener) {
+ mPropertyChangedListener->onPropertyChanged();
+ }
+ }
+ }
+
private:
- enum class Property {
- Rotate = 0,
- PivotX,
- PivotY,
- ScaleX,
- ScaleY,
- TranslateX,
- TranslateY,
- // Count of the properties, must be at the end.
- Count,
- };
+ GroupProperties mProperties = GroupProperties(this);
+ GroupProperties mStagingProperties = GroupProperties(this);
+ bool mStagingPropertiesDirty = true;
std::vector< std::unique_ptr<Node> > mChildren;
- Properties mProperties;
};
class ANDROID_API Tree : public VirtualLightRefBase {
public:
- Tree(Group* rootNode) : mRootNode(rootNode) {}
+ Tree(Group* rootNode) : mRootNode(rootNode) {
+ mRootNode->setPropertyChangedListener(&mPropertyChangedListener);
+ }
void draw(Canvas* outCanvas, SkColorFilter* colorFilter,
const SkRect& bounds, bool needsMirroring, bool canReuseCache);
+ void drawStaging(Canvas* canvas);
const SkBitmap& getBitmapUpdateIfDirty();
- void createCachedBitmapIfNeeded(int width, int height);
- bool canReuseBitmap(int width, int height);
void setAllowCaching(bool allowCaching) {
mAllowCaching = allowCaching;
}
- bool setRootAlpha(float rootAlpha) {
- return VD_SET_PROP(mRootAlpha, rootAlpha);
+ SkPaint* getPaint();
+ void syncProperties() {
+ if (mStagingProperties.mNonAnimatablePropertiesDirty) {
+ mProperties.syncNonAnimatableProperties(mStagingProperties);
+ mStagingProperties.mNonAnimatablePropertiesDirty = false;
+ }
+
+ if (mStagingProperties.mAnimatablePropertiesDirty) {
+ mProperties.syncAnimatableProperties(mStagingProperties);
+ } else {
+ mStagingProperties.syncAnimatableProperties(mProperties);
+ }
+ mStagingProperties.mAnimatablePropertiesDirty = false;
+ mRootNode->syncProperties();
}
- float getRootAlpha() {
- return mRootAlpha;
- }
- void setViewportSize(float viewportWidth, float viewportHeight) {
- mViewportWidth = viewportWidth;
- mViewportHeight = viewportHeight;
- }
- SkPaint* getPaint();
- const SkRect& getBounds() const {
- return mBounds;
- }
+ class TreeProperties {
+ public:
+ TreeProperties(Tree* tree) : mTree(tree) {}
+ // Properties that can only be modified by UI thread, therefore sync should
+ // only go from UI to RT
+ struct NonAnimatableProperties {
+ float viewportWidth = 0;
+ float viewportHeight = 0;
+ SkRect bounds;
+ int scaledWidth = 0;
+ int scaledHeight = 0;
+ SkColorFilter* colorFilter = nullptr;
+ ~NonAnimatableProperties() {
+ SkSafeUnref(colorFilter);
+ }
+ } mNonAnimatableProperties;
+ bool mNonAnimatablePropertiesDirty = true;
+
+ float mRootAlpha = 1.0f;
+ bool mAnimatablePropertiesDirty = true;
+
+ void syncNonAnimatableProperties(const TreeProperties& prop) {
+ // Copy over the data that can only be changed in UI thread
+ if (mNonAnimatableProperties.colorFilter != prop.mNonAnimatableProperties.colorFilter) {
+ SkRefCnt_SafeAssign(mNonAnimatableProperties.colorFilter,
+ prop.mNonAnimatableProperties.colorFilter);
+ }
+ mNonAnimatableProperties = prop.mNonAnimatableProperties;
+ }
+
+ void setViewportSize(float width, float height) {
+ if (mNonAnimatableProperties.viewportWidth != width
+ || mNonAnimatableProperties.viewportHeight != height) {
+ mNonAnimatablePropertiesDirty = true;
+ mNonAnimatableProperties.viewportWidth = width;
+ mNonAnimatableProperties.viewportHeight = height;
+ mTree->onPropertyChanged(this);
+ }
+ }
+ void setBounds(const SkRect& bounds) {
+ if (mNonAnimatableProperties.bounds != bounds) {
+ mNonAnimatableProperties.bounds = bounds;
+ mNonAnimatablePropertiesDirty = true;
+ mTree->onPropertyChanged(this);
+ }
+ }
+
+ void setScaledSize(int width, int height) {
+ if (mNonAnimatableProperties.scaledWidth != width
+ || mNonAnimatableProperties.scaledHeight != height) {
+ mNonAnimatableProperties.scaledWidth = width;
+ mNonAnimatableProperties.scaledHeight = height;
+ mNonAnimatablePropertiesDirty = true;
+ mTree->onPropertyChanged(this);
+ }
+ }
+ void setColorFilter(SkColorFilter* filter) {
+ if (UPDATE_SKPROP(mNonAnimatableProperties.colorFilter, filter)) {
+ mNonAnimatablePropertiesDirty = true;
+ mTree->onPropertyChanged(this);
+ }
+ }
+ SkColorFilter* getColorFilter() const{
+ return mNonAnimatableProperties.colorFilter;
+ }
+
+ float getViewportWidth() const {
+ return mNonAnimatableProperties.viewportWidth;
+ }
+ float getViewportHeight() const {
+ return mNonAnimatableProperties.viewportHeight;
+ }
+ float getScaledWidth() const {
+ return mNonAnimatableProperties.scaledWidth;
+ }
+ float getScaledHeight() const {
+ return mNonAnimatableProperties.scaledHeight;
+ }
+ void syncAnimatableProperties(const TreeProperties& prop) {
+ mRootAlpha = prop.mRootAlpha;
+ }
+ bool setRootAlpha(float rootAlpha) {
+ if (rootAlpha != mRootAlpha) {
+ mAnimatablePropertiesDirty = true;
+ mRootAlpha = rootAlpha;
+ mTree->onPropertyChanged(this);
+ return true;
+ }
+ return false;
+ }
+ float getRootAlpha() const { return mRootAlpha;}
+ const SkRect& getBounds() const {
+ return mNonAnimatableProperties.bounds;
+ }
+ Tree* mTree;
+ };
+ void onPropertyChanged(TreeProperties* prop);
+ TreeProperties* mutateStagingProperties() { return &mStagingProperties; }
+ const TreeProperties* stagingProperties() { return &mStagingProperties; }
+ PushStagingFunctor* getFunctor() { return &mFunctor;}
+
+ // This should only be called from animations on RT
+ TreeProperties* mutateProperties() { return &mProperties; }
private:
+ class VectorDrawableFunctor : public PushStagingFunctor {
+ public:
+ VectorDrawableFunctor(Tree* tree) : mTree(tree) {}
+ virtual void operator ()() {
+ mTree->syncProperties();
+ }
+ private:
+ Tree* mTree;
+ };
+
+ SkPaint* updatePaint(SkPaint* outPaint, TreeProperties* prop);
+ bool allocateBitmapIfNeeded(SkBitmap* outCache, int width, int height);
+ bool canReuseBitmap(const SkBitmap&, int width, int height);
+ void updateBitmapCache(SkBitmap* outCache, bool useStagingData);
// Cap the bitmap size, such that it won't hurt the performance too much
// and it won't crash due to a very large scale.
// The drawable will look blurry above this size.
const static int MAX_CACHED_BITMAP_SIZE;
- bool mCacheDirty = true;
bool mAllowCaching = true;
- float mViewportWidth = 0;
- float mViewportHeight = 0;
- float mRootAlpha = 1.0f;
-
std::unique_ptr<Group> mRootNode;
- SkRect mBounds;
- SkMatrix mCanvasMatrix;
- SkPaint mPaint;
- SkPathMeasure mPathMeasure;
- SkBitmap mCachedBitmap;
+ TreeProperties mProperties = TreeProperties(this);
+ TreeProperties mStagingProperties = TreeProperties(this);
+
+ VectorDrawableFunctor mFunctor = VectorDrawableFunctor(this);
+
+ SkPaint mPaint;
+ struct Cache {
+ SkBitmap bitmap;
+ bool dirty = true;
+ };
+
+ Cache mStagingCache;
+ Cache mCache;
+
+ PropertyChangedListener mPropertyChangedListener
+ = PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty);
};
} // namespace VectorDrawable
diff --git a/libs/hwui/renderstate/OffscreenBufferPool.cpp b/libs/hwui/renderstate/OffscreenBufferPool.cpp
index bb1a044..73b6c02 100644
--- a/libs/hwui/renderstate/OffscreenBufferPool.cpp
+++ b/libs/hwui/renderstate/OffscreenBufferPool.cpp
@@ -127,7 +127,7 @@
}
void OffscreenBufferPool::clear() {
- for (auto entry : mPool) {
+ for (auto& entry : mPool) {
delete entry.layer;
}
mPool.clear();
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 6933b2f..63fa788 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -576,7 +576,7 @@
static void destroyPrefetechedNode(RenderNode* node) {
ALOGW("Incorrectly called buildLayer on View: %s, destroying layer...", node->getName());
- node->destroyHardwareResources();
+ node->destroyHardwareResources(nullptr);
node->decStrong(nullptr);
}
@@ -641,7 +641,7 @@
if (mEglManager.hasEglContext()) {
freePrefetechedLayers();
for (const sp<RenderNode>& node : mRenderNodes) {
- node->destroyHardwareResources();
+ node->destroyHardwareResources(nullptr);
}
Caches& caches = Caches::getInstance();
// Make sure to release all the textures we were owning as there won't
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 04223a7..16dd108 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -56,6 +56,7 @@
enum {
FrameStats = 1 << 0,
Reset = 1 << 1,
+ JankStats = 1 << 2,
};
};
@@ -415,7 +416,6 @@
CREATE_BRIDGE4(dumpProfileInfo, CanvasContext* context, RenderThread* thread,
int fd, int dumpFlags) {
args->context->profiler().dumpData(args->fd);
- args->thread->jankTracker().dump(args->fd);
if (args->dumpFlags & DumpFlags::FrameStats) {
args->context->dumpFrames(args->fd);
}
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 2d1e2e9..5492035 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -218,7 +218,7 @@
private:
static void syncHierarchyPropertiesAndDisplayListImpl(RenderNode* node) {
node->syncProperties();
- node->syncDisplayList();
+ node->syncDisplayList(nullptr);
auto displayList = node->getDisplayList();
if (displayList) {
for (auto&& childOp : displayList->getChildren()) {
diff --git a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
index 654ddc6..5471486 100644
--- a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
@@ -85,7 +85,9 @@
<< "Should see conservative offset from PathCache::computeBounds";
Rect expectedBounds(10, 15, 20, 25);
expectedBounds.outset(expectedOffset);
+#if !HWUI_NEW_OPS
EXPECT_EQ(expectedBounds, glop.bounds) << "bounds outset by stroke 'offset'";
+#endif
Matrix4 expectedModelView;
expectedModelView.loadTranslate(10 - expectedOffset, 15 - expectedOffset, 0);
expectedModelView.scale(10 + 2 * expectedOffset, 10 + 2 * expectedOffset, 1);
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index 7dfafb9..0ea246f 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -49,9 +49,12 @@
public:
virtual ~TestRendererBase() {}
virtual OffscreenBuffer* startTemporaryLayer(uint32_t, uint32_t) {
- ADD_FAILURE() << "Layer creation not expected in this test";
+ ADD_FAILURE() << "Temporary layers not expected in this test";
return nullptr;
}
+ virtual void recycleTemporaryLayer(OffscreenBuffer*) {
+ ADD_FAILURE() << "Temporary layers not expected in this test";
+ }
virtual void startRepaintLayer(OffscreenBuffer*, const Rect& repaintRect) {
ADD_FAILURE() << "Layer repaint not expected in this test";
}
@@ -298,7 +301,6 @@
class AvoidOverdrawBitmapsTestRenderer : public TestRendererBase {
public:
void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
- EXPECT_LT(mIndex++, 2) << "Should be two bitmaps";
switch(mIndex++) {
case 0:
EXPECT_EQ(opaqueBitmap.pixelRef(), op.bitmap->pixelRef());
@@ -331,7 +333,7 @@
AvoidOverdrawBitmapsTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
- EXPECT_EQ(2, renderer.getIndex()) << "Expect exactly one op";
+ EXPECT_EQ(2, renderer.getIndex()) << "Expect exactly two ops";
}
RENDERTHREAD_TEST(FrameBuilder, clippedMerging) {
@@ -711,6 +713,10 @@
EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
EXPECT_TRUE(state.computedState.transform.isIdentity());
}
+ void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
+ EXPECT_EQ(4, mIndex++);
+ EXPECT_EQ(nullptr, offscreenBuffer);
+ }
};
auto node = TestUtils::createNode(0, 0, 200, 200,
@@ -723,7 +729,7 @@
TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
SaveLayerSimpleTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
- EXPECT_EQ(4, renderer.getIndex());
+ EXPECT_EQ(5, renderer.getIndex());
}
RENDERTHREAD_TEST(FrameBuilder, saveLayer_nested) {
@@ -775,6 +781,15 @@
EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer
} else { ADD_FAILURE(); }
}
+ void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
+ const int index = mIndex++;
+ // order isn't important, but we need to see both
+ if (index == 10) {
+ EXPECT_EQ((OffscreenBuffer*)0x400, offscreenBuffer);
+ } else if (index == 11) {
+ EXPECT_EQ((OffscreenBuffer*)0x800, offscreenBuffer);
+ } else { ADD_FAILURE(); }
+ }
};
auto node = TestUtils::createNode(0, 0, 800, 800,
@@ -795,7 +810,7 @@
TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
SaveLayerNestedTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
- EXPECT_EQ(10, renderer.getIndex());
+ EXPECT_EQ(12, renderer.getIndex());
}
RENDERTHREAD_TEST(FrameBuilder, saveLayer_contentRejection) {
@@ -1010,10 +1025,15 @@
}
void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
EXPECT_EQ(9, mIndex++);
+ EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
}
void endFrame(const Rect& repaintRect) override {
EXPECT_EQ(11, mIndex++);
}
+ void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
+ EXPECT_EQ(12, mIndex++);
+ EXPECT_EQ((OffscreenBuffer*)0xabcd, offscreenBuffer);
+ }
};
auto node = TestUtils::createNode(0, 0, 600, 600, // 500x500 triggers clipping
@@ -1030,7 +1050,7 @@
TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
SaveLayerUnclippedComplexTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
- EXPECT_EQ(12, renderer.getIndex());
+ EXPECT_EQ(13, renderer.getIndex());
}
RENDERTHREAD_TEST(FrameBuilder, hwLayer_simple) {
@@ -1152,6 +1172,9 @@
void endFrame(const Rect& repaintRect) override {
EXPECT_EQ(12, mIndex++);
}
+ void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
+ EXPECT_EQ(13, mIndex++);
+ }
};
auto child = TestUtils::createNode(50, 50, 150, 150,
@@ -1189,7 +1212,7 @@
syncedList, sLightGeometry, Caches::getInstance());
HwLayerComplexTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
- EXPECT_EQ(13, renderer.getIndex());
+ EXPECT_EQ(14, renderer.getIndex());
// clean up layer pointers, so we can safely destruct RenderNodes
*(child->getLayerHandle()) = nullptr;
@@ -1593,6 +1616,9 @@
void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
EXPECT_EQ(4, mIndex++);
}
+ void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
+ EXPECT_EQ(5, mIndex++);
+ }
};
auto parent = TestUtils::createNode(0, 0, 200, 200,
@@ -1611,7 +1637,7 @@
(FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
ShadowSaveLayerTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
- EXPECT_EQ(5, renderer.getIndex());
+ EXPECT_EQ(6, renderer.getIndex());
}
RENDERTHREAD_TEST(FrameBuilder, shadowHwLayer) {
@@ -1840,6 +1866,9 @@
void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
EXPECT_EQ(3, mIndex++);
}
+ void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
+ EXPECT_EQ(4, mIndex++);
+ }
private:
SaveLayerAlphaData* mOutData;
};
@@ -1865,7 +1894,7 @@
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
// assert, since output won't be valid if we haven't seen a save layer triggered
- ASSERT_EQ(4, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior.";
+ ASSERT_EQ(5, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior.";
}
RENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
diff --git a/libs/hwui/tests/unit/GlopBuilderTests.cpp b/libs/hwui/tests/unit/GlopBuilderTests.cpp
index 454011f..95543d3 100644
--- a/libs/hwui/tests/unit/GlopBuilderTests.cpp
+++ b/libs/hwui/tests/unit/GlopBuilderTests.cpp
@@ -85,7 +85,9 @@
}
static void expectGlopEq(Glop& expectedGlop, Glop& builtGlop) {
+#if !HWUI_NEW_OPS
EXPECT_EQ(expectedGlop.bounds, builtGlop.bounds);
+#endif
expectBlendEq(expectedGlop.blend, builtGlop.blend);
expectFillEq(expectedGlop.fill, builtGlop.fill);
expectMeshEq(expectedGlop.mesh, builtGlop.mesh);
@@ -136,7 +138,9 @@
// unit quad also should be translate by additional (0.3, 0.3) to snap to exact pixels.
goldenGlop->transform.modelView.loadTranslate(1.3, 1.3, 0);
goldenGlop->transform.modelView.scale(99, 99, 1);
+#if !HWUI_NEW_OPS
goldenGlop->bounds = android::uirenderer::Rect(1.70, 1.70, 100.70, 100.70);
+#endif
goldenGlop->transform.canvas = simpleTranslate;
goldenGlop->fill.texture.filter = GL_NEAREST;
expectGlopEq(*goldenGlop, glop);
diff --git a/libs/hwui/tests/unit/LeakCheckTests.cpp b/libs/hwui/tests/unit/LeakCheckTests.cpp
index 9161f90..e2fc376 100644
--- a/libs/hwui/tests/unit/LeakCheckTests.cpp
+++ b/libs/hwui/tests/unit/LeakCheckTests.cpp
@@ -30,6 +30,25 @@
const FrameBuilder::LightGeometry sLightGeometery = { {100, 100, 100}, 50};
const BakedOpRenderer::LightInfo sLightInfo = { 128, 128 };
+RENDERTHREAD_TEST(LeakCheck, saveLayer_overdrawRejection) {
+ auto node = TestUtils::createNode(0, 0, 100, 100,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.saveLayerAlpha(0, 0, 100, 100, 128, SaveFlags::ClipToLayer);
+ canvas.drawRect(0, 0, 100, 100, SkPaint());
+ canvas.restore();
+
+ // opaque draw, rejects saveLayer beneath
+ canvas.drawRect(0, 0, 100, 100, SkPaint());
+ });
+ RenderState& renderState = renderThread.renderState();
+ Caches& caches = Caches::getInstance();
+
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
+ TestUtils::createSyncedNodeList(node), sLightGeometery, Caches::getInstance());
+ BakedOpRenderer renderer(caches, renderState, true, sLightInfo);
+ frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
+}
+
RENDERTHREAD_TEST(LeakCheck, saveLayerUnclipped_simple) {
auto node = TestUtils::createNode(0, 0, 200, 200,
[](RenderProperties& props, RecordingCanvas& canvas) {
diff --git a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
index 37a485e..b7950aa 100644
--- a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
+++ b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
@@ -30,119 +30,126 @@
EXPECT_EQ(1024u, OffscreenBuffer::computeIdealDimension(1000));
}
-TEST(OffscreenBuffer, construct) {
- TestUtils::runOnRenderThread([] (renderthread::RenderThread& thread) {
- OffscreenBuffer layer(thread.renderState(), Caches::getInstance(), 49u, 149u);
- EXPECT_EQ(49u, layer.viewportWidth);
- EXPECT_EQ(149u, layer.viewportHeight);
+RENDERTHREAD_TEST(OffscreenBuffer, construct) {
+ OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 49u, 149u);
+ EXPECT_EQ(49u, layer.viewportWidth);
+ EXPECT_EQ(149u, layer.viewportHeight);
- EXPECT_EQ(64u, layer.texture.width());
- EXPECT_EQ(192u, layer.texture.height());
+ EXPECT_EQ(64u, layer.texture.width());
+ EXPECT_EQ(192u, layer.texture.height());
- EXPECT_EQ(64u * 192u * 4u, layer.getSizeInBytes());
- });
+ EXPECT_EQ(64u * 192u * 4u, layer.getSizeInBytes());
}
-TEST(OffscreenBuffer, getTextureCoordinates) {
- TestUtils::runOnRenderThread([] (renderthread::RenderThread& thread) {
- OffscreenBuffer layerAligned(thread.renderState(), Caches::getInstance(), 256u, 256u);
- EXPECT_EQ(Rect(0, 1, 1, 0),
- layerAligned.getTextureCoordinates());
+RENDERTHREAD_TEST(OffscreenBuffer, getTextureCoordinates) {
+ OffscreenBuffer layerAligned(renderThread.renderState(), Caches::getInstance(), 256u, 256u);
+ EXPECT_EQ(Rect(0, 1, 1, 0),
+ layerAligned.getTextureCoordinates());
- OffscreenBuffer layerUnaligned(thread.renderState(), Caches::getInstance(), 200u, 225u);
- EXPECT_EQ(Rect(0, 225.0f / 256.0f, 200.0f / 256.0f, 0),
- layerUnaligned.getTextureCoordinates());
- });
+ OffscreenBuffer layerUnaligned(renderThread.renderState(), Caches::getInstance(), 200u, 225u);
+ EXPECT_EQ(Rect(0, 225.0f / 256.0f, 200.0f / 256.0f, 0),
+ layerUnaligned.getTextureCoordinates());
}
-TEST(OffscreenBuffer, dirty) {
- TestUtils::runOnRenderThread([] (renderthread::RenderThread& thread) {
- OffscreenBuffer buffer(thread.renderState(), Caches::getInstance(), 256u, 256u);
- buffer.dirty(Rect(-100, -100, 100, 100));
- EXPECT_EQ(android::Rect(100, 100), buffer.region.getBounds());
- });
+RENDERTHREAD_TEST(OffscreenBuffer, dirty) {
+ OffscreenBuffer buffer(renderThread.renderState(), Caches::getInstance(), 256u, 256u);
+ buffer.dirty(Rect(-100, -100, 100, 100));
+ EXPECT_EQ(android::Rect(100, 100), buffer.region.getBounds());
}
-TEST(OffscreenBufferPool, construct) {
- TestUtils::runOnRenderThread([] (renderthread::RenderThread& thread) {
- OffscreenBufferPool pool;
- EXPECT_EQ(0u, pool.getCount()) << "pool must be created empty";
- EXPECT_EQ(0u, pool.getSize()) << "pool must be created empty";
- EXPECT_EQ((uint32_t) Properties::layerPoolSize, pool.getMaxSize())
- << "pool must read size from Properties";
- });
+RENDERTHREAD_TEST(OffscreenBufferPool, construct) {
+ OffscreenBufferPool pool;
+ EXPECT_EQ(0u, pool.getCount()) << "pool must be created empty";
+ EXPECT_EQ(0u, pool.getSize()) << "pool must be created empty";
+ EXPECT_EQ((uint32_t) Properties::layerPoolSize, pool.getMaxSize())
+ << "pool must read size from Properties";
}
-TEST(OffscreenBufferPool, getPutClear) {
- TestUtils::runOnRenderThread([] (renderthread::RenderThread& thread) {
- OffscreenBufferPool pool;
+RENDERTHREAD_TEST(OffscreenBufferPool, getPutClear) {
+ OffscreenBufferPool pool;
- auto layer = pool.get(thread.renderState(), 100u, 200u);
- EXPECT_EQ(100u, layer->viewportWidth);
- EXPECT_EQ(200u, layer->viewportHeight);
+ auto layer = pool.get(renderThread.renderState(), 100u, 200u);
+ EXPECT_EQ(100u, layer->viewportWidth);
+ EXPECT_EQ(200u, layer->viewportHeight);
- ASSERT_LT(layer->getSizeInBytes(), pool.getMaxSize());
+ ASSERT_LT(layer->getSizeInBytes(), pool.getMaxSize());
- pool.putOrDelete(layer);
- ASSERT_EQ(layer->getSizeInBytes(), pool.getSize());
+ pool.putOrDelete(layer);
+ ASSERT_EQ(layer->getSizeInBytes(), pool.getSize());
- auto layer2 = pool.get(thread.renderState(), 102u, 202u);
- EXPECT_EQ(layer, layer2) << "layer should be recycled";
- ASSERT_EQ(0u, pool.getSize()) << "pool should have been emptied by removing only layer";
+ auto layer2 = pool.get(renderThread.renderState(), 102u, 202u);
+ EXPECT_EQ(layer, layer2) << "layer should be recycled";
+ ASSERT_EQ(0u, pool.getSize()) << "pool should have been emptied by removing only layer";
- pool.putOrDelete(layer);
- EXPECT_EQ(1u, pool.getCount());
- pool.clear();
- EXPECT_EQ(0u, pool.getSize());
- EXPECT_EQ(0u, pool.getCount());
- });
+ pool.putOrDelete(layer);
+ EXPECT_EQ(1u, pool.getCount());
+ pool.clear();
+ EXPECT_EQ(0u, pool.getSize());
+ EXPECT_EQ(0u, pool.getCount());
}
-TEST(OffscreenBufferPool, resize) {
- TestUtils::runOnRenderThread([] (renderthread::RenderThread& thread) {
- OffscreenBufferPool pool;
+RENDERTHREAD_TEST(OffscreenBufferPool, resize) {
+ OffscreenBufferPool pool;
- auto layer = pool.get(thread.renderState(), 64u, 64u);
- layer->dirty(Rect(64, 64));
+ auto layer = pool.get(renderThread.renderState(), 64u, 64u);
+ layer->dirty(Rect(64, 64));
- // resize in place
- ASSERT_EQ(layer, pool.resize(layer, 60u, 55u));
- EXPECT_TRUE(layer->region.isEmpty()) << "In place resize should clear usage region";
- EXPECT_EQ(60u, layer->viewportWidth);
- EXPECT_EQ(55u, layer->viewportHeight);
- EXPECT_EQ(64u, layer->texture.width());
- EXPECT_EQ(64u, layer->texture.height());
+ // resize in place
+ ASSERT_EQ(layer, pool.resize(layer, 60u, 55u));
+ EXPECT_TRUE(layer->region.isEmpty()) << "In place resize should clear usage region";
+ EXPECT_EQ(60u, layer->viewportWidth);
+ EXPECT_EQ(55u, layer->viewportHeight);
+ EXPECT_EQ(64u, layer->texture.width());
+ EXPECT_EQ(64u, layer->texture.height());
- // resized to use different object in pool
- auto layer2 = pool.get(thread.renderState(), 128u, 128u);
- layer2->dirty(Rect(128, 128));
- EXPECT_FALSE(layer2->region.isEmpty());
- pool.putOrDelete(layer2);
- ASSERT_EQ(1u, pool.getCount());
+ // resized to use different object in pool
+ auto layer2 = pool.get(renderThread.renderState(), 128u, 128u);
+ layer2->dirty(Rect(128, 128));
+ EXPECT_FALSE(layer2->region.isEmpty());
+ pool.putOrDelete(layer2);
+ ASSERT_EQ(1u, pool.getCount());
- ASSERT_EQ(layer2, pool.resize(layer, 120u, 125u));
- EXPECT_TRUE(layer2->region.isEmpty()) << "Swap resize should clear usage region";
- EXPECT_EQ(120u, layer2->viewportWidth);
- EXPECT_EQ(125u, layer2->viewportHeight);
- EXPECT_EQ(128u, layer2->texture.width());
- EXPECT_EQ(128u, layer2->texture.height());
+ ASSERT_EQ(layer2, pool.resize(layer, 120u, 125u));
+ EXPECT_TRUE(layer2->region.isEmpty()) << "Swap resize should clear usage region";
+ EXPECT_EQ(120u, layer2->viewportWidth);
+ EXPECT_EQ(125u, layer2->viewportHeight);
+ EXPECT_EQ(128u, layer2->texture.width());
+ EXPECT_EQ(128u, layer2->texture.height());
- // original allocation now only thing in pool
- EXPECT_EQ(1u, pool.getCount());
- EXPECT_EQ(layer->getSizeInBytes(), pool.getSize());
+ // original allocation now only thing in pool
+ EXPECT_EQ(1u, pool.getCount());
+ EXPECT_EQ(layer->getSizeInBytes(), pool.getSize());
- pool.putOrDelete(layer2);
- });
+ pool.putOrDelete(layer2);
}
-TEST(OffscreenBufferPool, putAndDestroy) {
- TestUtils::runOnRenderThread([] (renderthread::RenderThread& thread) {
- OffscreenBufferPool pool;
- // layer too big to return to the pool
- // Note: this relies on the fact that the pool won't reject based on max texture size
- auto hugeLayer = pool.get(thread.renderState(), pool.getMaxSize() / 64, 64);
- EXPECT_GT(hugeLayer->getSizeInBytes(), pool.getMaxSize());
- pool.putOrDelete(hugeLayer);
- EXPECT_EQ(0u, pool.getCount()); // failed to put (so was destroyed instead)
- });
+RENDERTHREAD_TEST(OffscreenBufferPool, putAndDestroy) {
+ OffscreenBufferPool pool;
+ // layer too big to return to the pool
+ // Note: this relies on the fact that the pool won't reject based on max texture size
+ auto hugeLayer = pool.get(renderThread.renderState(), pool.getMaxSize() / 64, 64);
+ EXPECT_GT(hugeLayer->getSizeInBytes(), pool.getMaxSize());
+ pool.putOrDelete(hugeLayer);
+ EXPECT_EQ(0u, pool.getCount()); // failed to put (so was destroyed instead)
+}
+
+RENDERTHREAD_TEST(OffscreenBufferPool, clear) {
+ EXPECT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::OffscreenBuffer));
+ OffscreenBufferPool pool;
+
+ // Create many buffers, with several at each size
+ std::vector<OffscreenBuffer*> buffers;
+ for (int size = 32; size <= 128; size += 32) {
+ for (int i = 0; i < 10; i++) {
+ buffers.push_back(pool.get(renderThread.renderState(), size, size));
+ }
+ }
+ EXPECT_EQ(0u, pool.getCount()) << "Expect nothing inside";
+ for (auto& buffer : buffers) pool.putOrDelete(buffer);
+ EXPECT_EQ(40u, pool.getCount()) << "Expect all items added";
+ EXPECT_EQ(40, GpuMemoryTracker::getInstanceCount(GpuObjectType::OffscreenBuffer));
+ pool.clear();
+ EXPECT_EQ(0u, pool.getCount()) << "Expect all items cleared";
+
+ EXPECT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::OffscreenBuffer));
}
diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp
new file mode 100644
index 0000000..7c57a50
--- /dev/null
+++ b/libs/hwui/tests/unit/RenderNodeTests.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "RenderNode.h"
+#include "TreeInfo.h"
+#include "tests/common/TestUtils.h"
+#include "utils/Color.h"
+
+using namespace android;
+using namespace android::uirenderer;
+
+TEST(RenderNode, hasParents) {
+ auto child = TestUtils::createNode(0, 0, 200, 400,
+ [](RenderProperties& props, TestCanvas& canvas) {
+ canvas.drawColor(Color::Red_500, SkXfermode::kSrcOver_Mode);
+ });
+ auto parent = TestUtils::createNode(0, 0, 200, 400,
+ [&child](RenderProperties& props, TestCanvas& canvas) {
+ canvas.drawRenderNode(child.get());
+ });
+
+ TestUtils::syncHierarchyPropertiesAndDisplayList(parent);
+
+ EXPECT_TRUE(child->hasParents()) << "Child node has no parent";
+ EXPECT_FALSE(parent->hasParents()) << "Root node shouldn't have any parents";
+
+ TestUtils::recordNode(*parent, [](TestCanvas& canvas) {
+ canvas.drawColor(Color::Amber_500, SkXfermode::kSrcOver_Mode);
+ });
+
+ EXPECT_TRUE(child->hasParents()) << "Child should still have a parent";
+ EXPECT_FALSE(parent->hasParents()) << "Root node shouldn't have any parents";
+
+ TestUtils::syncHierarchyPropertiesAndDisplayList(parent);
+
+ EXPECT_FALSE(child->hasParents()) << "Child should be removed";
+ EXPECT_FALSE(parent->hasParents()) << "Root node shouldn't have any parents";
+}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 0a8c692..00eff91 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -2157,7 +2157,7 @@
final RecordConfigChangeCallbackData cbData =
(RecordConfigChangeCallbackData) msg.obj;
if (cbData.mCb != null) {
- cbData.mCb.onRecordConfigChanged(cbData.mConfigs);
+ cbData.mCb.onRecordingConfigChanged(cbData.mConfigs);
}
break;
default:
@@ -2746,7 +2746,7 @@
* @param configs array containing the results of
* {@link AudioManager#getActiveRecordingConfigurations()}.
*/
- public void onRecordConfigChanged(AudioRecordingConfiguration[] configs) {}
+ public void onRecordingConfigChanged(AudioRecordingConfiguration[] configs) {}
}
private static class AudioRecordingCallbackInfo {
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index b6ff41e..621129d 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -596,14 +596,14 @@
* AudioTrack player = new AudioTrack.Builder()
* .setAudioAttributes(new AudioAttributes.Builder()
* .setUsage(AudioAttributes.USAGE_ALARM)
- * .setContentType(CONTENT_TYPE_MUSIC)
+ * .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
* .build())
* .setAudioFormat(new AudioFormat.Builder()
* .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
- * .setSampleRate(441000)
+ * .setSampleRate(44100)
* .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
* .build())
- * .setBufferSize(minBuffSize)
+ * .setBufferSizeInBytes(minBuffSize)
* .build();
* </pre>
* <p>
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 9cad005..3d7e744 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -161,9 +161,14 @@
public static final String TAG_EXPOSURE_PROGRAM = "ExposureProgram";
/** Type is double. */
public static final String TAG_EXPOSURE_TIME = "ExposureTime";
- /** Type is String. */
+ /** Type is double. */
public static final String TAG_F_NUMBER = "FNumber";
- /** Type is String. */
+ /**
+ * Type is double.
+ *
+ * @deprecated use {@link #TAG_F_NUMBER} instead
+ */
+ @Deprecated
public static final String TAG_APERTURE = "FNumber";
/** Type is String. */
public static final String TAG_FILE_SOURCE = "FileSource";
@@ -185,9 +190,14 @@
public static final String TAG_FOCAL_PLANE_Y_RESOLUTION = "FocalPlaneYResolution";
/** Type is rational. */
public static final String TAG_GAIN_CONTROL = "GainControl";
- /** Type is String. */
+ /** Type is int. */
public static final String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
- /** Type is String. */
+ /**
+ * Type is int.
+ *
+ * @deprecated use {@link #TAG_ISO_SPEED_RATINGS} instead
+ */
+ @Deprecated
public static final String TAG_ISO = "ISOSpeedRatings";
/** Type is String. */
public static final String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
@@ -225,8 +235,6 @@
public static final String TAG_SPECTRAL_SENSITIVITY = "SpectralSensitivity";
/** Type is int. */
public static final String TAG_SUBSEC_TIME = "SubSecTime";
- /** Type is int. @hide */
- public static final String TAG_SUBSECTIME = "SubSecTime";
/** Type is int. */
public static final String TAG_SUBSEC_TIME_DIGITIZED = "SubSecTimeDigitized";
/** Type is int. */
@@ -437,7 +445,7 @@
new ExifTag(TAG_F_NUMBER, 33437),
new ExifTag(TAG_EXPOSURE_PROGRAM, 34850),
new ExifTag(TAG_SPECTRAL_SENSITIVITY, 34852),
- new ExifTag(TAG_ISO, 34855),
+ new ExifTag(TAG_ISO_SPEED_RATINGS, 34855),
new ExifTag(TAG_OECF, 34856),
new ExifTag(TAG_EXIF_VERSION, 36864),
new ExifTag(TAG_DATETIME_ORIGINAL, 36867),
@@ -1151,7 +1159,7 @@
if (datetime == null) return -1;
long msecs = datetime.getTime();
- String subSecs = getAttribute(TAG_SUBSECTIME);
+ String subSecs = getAttribute(TAG_SUBSEC_TIME);
if (subSecs != null) {
try {
long sub = Long.valueOf(subSecs);
@@ -1543,7 +1551,7 @@
convertToDouble(TAG_EXPOSURE_TIME);
convertToDouble(TAG_F_NUMBER);
convertToDouble(TAG_SUBJECT_DISTANCE);
- convertToInt(TAG_ISO);
+ convertToInt(TAG_ISO_SPEED_RATINGS);
convertToDouble(TAG_EXPOSURE_BIAS_VALUE);
convertToInt(TAG_WHITE_BALANCE);
convertToInt(TAG_LIGHT_SOURCE);
diff --git a/media/java/android/media/MediaActionSound.java b/media/java/android/media/MediaActionSound.java
index 1fee587..983ca75 100644
--- a/media/java/android/media/MediaActionSound.java
+++ b/media/java/android/media/MediaActionSound.java
@@ -45,8 +45,7 @@
private static final int NUM_MEDIA_SOUND_STREAMS = 1;
private SoundPool mSoundPool;
- private int[] mSoundIds;
- private int mSoundIdToPlay;
+ private SoundState[] mSounds;
private static final String[] SOUND_FILES = {
"/system/media/audio/ui/camera_click.ogg",
@@ -88,22 +87,57 @@
*/
public static final int STOP_VIDEO_RECORDING = 3;
- private static final int SOUND_NOT_LOADED = -1;
+ /**
+ * States for SoundState.
+ * STATE_NOT_LOADED : sample not loaded
+ * STATE_LOADING : sample being loaded: waiting for load completion callback
+ * STATE_LOADING_PLAY_REQUESTED : sample being loaded and playback request received
+ * STATE_LOADED : sample loaded, ready for playback
+ */
+ private static final int STATE_NOT_LOADED = 0;
+ private static final int STATE_LOADING = 1;
+ private static final int STATE_LOADING_PLAY_REQUESTED = 2;
+ private static final int STATE_LOADED = 3;
+ private class SoundState {
+ public final int name;
+ public int id;
+ public int state;
+
+ public SoundState(int name) {
+ this.name = name;
+ id = 0; // 0 is an invalid sample ID.
+ state = STATE_NOT_LOADED;
+ }
+ }
/**
* Construct a new MediaActionSound instance. Only a single instance is
* needed for playing any platform media action sound; you do not need a
* separate instance for each sound type.
*/
public MediaActionSound() {
- mSoundPool = new SoundPool(NUM_MEDIA_SOUND_STREAMS,
- AudioManager.STREAM_SYSTEM_ENFORCED, 0);
+ mSoundPool = new SoundPool.Builder()
+ .setMaxStreams(NUM_MEDIA_SOUND_STREAMS)
+ .setAudioAttributes(new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+ .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .build())
+ .build();
mSoundPool.setOnLoadCompleteListener(mLoadCompleteListener);
- mSoundIds = new int[SOUND_FILES.length];
- for (int i = 0; i < mSoundIds.length; i++) {
- mSoundIds[i] = SOUND_NOT_LOADED;
+ mSounds = new SoundState[SOUND_FILES.length];
+ for (int i = 0; i < mSounds.length; i++) {
+ mSounds[i] = new SoundState(i);
}
- mSoundIdToPlay = SOUND_NOT_LOADED;
+ }
+
+ private int loadSound(SoundState sound) {
+ int id = mSoundPool.load(SOUND_FILES[sound.name], 1);
+ if (id > 0) {
+ sound.state = STATE_LOADING;
+ sound.id = id;
+ }
+ return id;
}
/**
@@ -118,13 +152,22 @@
* @see #START_VIDEO_RECORDING
* @see #STOP_VIDEO_RECORDING
*/
- public synchronized void load(int soundName) {
+ public void load(int soundName) {
if (soundName < 0 || soundName >= SOUND_FILES.length) {
throw new RuntimeException("Unknown sound requested: " + soundName);
}
- if (mSoundIds[soundName] == SOUND_NOT_LOADED) {
- mSoundIds[soundName] =
- mSoundPool.load(SOUND_FILES[soundName], 1);
+ SoundState sound = mSounds[soundName];
+ synchronized (sound) {
+ switch (sound.state) {
+ case STATE_NOT_LOADED:
+ if (loadSound(sound) <= 0) {
+ Log.e(TAG, "load() error loading sound: " + soundName);
+ }
+ break;
+ default:
+ Log.e(TAG, "load() called in wrong state: " + sound + " for sound: "+ soundName);
+ break;
+ }
}
}
@@ -159,16 +202,31 @@
* @see #START_VIDEO_RECORDING
* @see #STOP_VIDEO_RECORDING
*/
- public synchronized void play(int soundName) {
+ public void play(int soundName) {
if (soundName < 0 || soundName >= SOUND_FILES.length) {
throw new RuntimeException("Unknown sound requested: " + soundName);
}
- if (mSoundIds[soundName] == SOUND_NOT_LOADED) {
- mSoundIdToPlay =
- mSoundPool.load(SOUND_FILES[soundName], 1);
- mSoundIds[soundName] = mSoundIdToPlay;
- } else {
- mSoundPool.play(mSoundIds[soundName], 1.0f, 1.0f, 0, 0, 1.0f);
+ SoundState sound = mSounds[soundName];
+ synchronized (sound) {
+ switch (sound.state) {
+ case STATE_NOT_LOADED:
+ loadSound(sound);
+ if (loadSound(sound) <= 0) {
+ Log.e(TAG, "play() error loading sound: " + soundName);
+ break;
+ }
+ // FALL THROUGH
+
+ case STATE_LOADING:
+ sound.state = STATE_LOADING_PLAY_REQUESTED;
+ break;
+ case STATE_LOADED:
+ mSoundPool.play(sound.id, 1.0f, 1.0f, 0, 0, 1.0f);
+ break;
+ default:
+ Log.e(TAG, "play() called in wrong state: " + sound.state + " for sound: "+ soundName);
+ break;
+ }
}
}
@@ -176,14 +234,37 @@
new SoundPool.OnLoadCompleteListener() {
public void onLoadComplete(SoundPool soundPool,
int sampleId, int status) {
- if (status == 0) {
- if (mSoundIdToPlay == sampleId) {
- soundPool.play(sampleId, 1.0f, 1.0f, 0, 0, 1.0f);
- mSoundIdToPlay = SOUND_NOT_LOADED;
+ for (SoundState sound : mSounds) {
+ if (sound.id != sampleId) {
+ continue;
}
- } else {
- Log.e(TAG, "Unable to load sound for playback (status: " +
- status + ")");
+ int playSoundId = 0;
+ synchronized (sound) {
+ if (status != 0) {
+ sound.state = STATE_NOT_LOADED;
+ sound.id = 0;
+ Log.e(TAG, "OnLoadCompleteListener() error: " + status +
+ " loading sound: "+ sound.name);
+ return;
+ }
+ switch (sound.state) {
+ case STATE_LOADING:
+ sound.state = STATE_LOADED;
+ break;
+ case STATE_LOADING_PLAY_REQUESTED:
+ playSoundId = sound.id;
+ sound.state = STATE_LOADED;
+ break;
+ default:
+ Log.e(TAG, "OnLoadCompleteListener() called in wrong state: "
+ + sound.state + " for sound: "+ sound.name);
+ break;
+ }
+ }
+ if (playSoundId != 0) {
+ soundPool.play(playSoundId, 1.0f, 1.0f, 0, 0, 1.0f);
+ }
+ break;
}
}
};
@@ -195,6 +276,12 @@
*/
public void release() {
if (mSoundPool != null) {
+ for (SoundState sound : mSounds) {
+ synchronized (sound) {
+ sound.state = STATE_NOT_LOADED;
+ sound.id = 0;
+ }
+ }
mSoundPool.release();
mSoundPool = null;
}
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index b1c1b79..2bd9781 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -2666,12 +2666,13 @@
public static final int HEVCHighTierLevel62 = 0x2000000;
// from OMX_VIDEO_DOLBYVISIONPROFILETYPE
- public static final int DolbyVisionProfileDvavDer = 0x1;
- public static final int DolbyVisionProfileDvavDen = 0x2;
- public static final int DolbyVisionProfileDvheDer = 0x3;
- public static final int DolbyVisionProfileDvheDen = 0x4;
- public static final int DolbyVisionProfileDvheDtr = 0x5;
- public static final int DolbyVisionProfileDvheStn = 0x6;
+ public static final int DolbyVisionProfileDvavPer = 0x1;
+ public static final int DolbyVisionProfileDvavPen = 0x2;
+ public static final int DolbyVisionProfileDvheDer = 0x4;
+ public static final int DolbyVisionProfileDvheDen = 0x8;
+ public static final int DolbyVisionProfileDvheDtr = 0x10;
+ public static final int DolbyVisionProfileDvheStn = 0x20;
+ public static final int DolbyVisionProfileDvheDth = 0x40;
// from OMX_VIDEO_DOLBYVISIONLEVELTYPE
public static final int DolbyVisionLevelHd24 = 0x1;
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 177344a..24a400e4 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -275,16 +275,23 @@
return initDataMap.get(schemeUuid);
}
};
- } else if (formatMap.containsKey("crypto-key")) {
- ByteBuffer buf = (ByteBuffer) formatMap.get("crypto-key");
- buf.rewind();
- final byte[] data = new byte[buf.remaining()];
- buf.get(data);
- return new DrmInitData() {
- public SchemeInitData get(UUID schemeUuid) {
- return new DrmInitData.SchemeInitData("webm", data);
+ } else {
+ int numTracks = getTrackCount();
+ for (int i = 0; i < numTracks; ++i) {
+ Map<String, Object> trackFormatMap = getTrackFormatNative(i);
+ if (!trackFormatMap.containsKey("crypto-key")) {
+ continue;
}
- };
+ ByteBuffer buf = (ByteBuffer) trackFormatMap.get("crypto-key");
+ buf.rewind();
+ final byte[] data = new byte[buf.remaining()];
+ buf.get(data);
+ return new DrmInitData() {
+ public SchemeInitData get(UUID schemeUuid) {
+ return new DrmInitData.SchemeInitData("webm", data);
+ }
+ };
+ }
}
return null;
}
diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java
index ebe509c..7117fbd 100644
--- a/media/java/android/media/MediaMuxer.java
+++ b/media/java/android/media/MediaMuxer.java
@@ -34,7 +34,7 @@
/**
* MediaMuxer facilitates muxing elementary streams. Currently supports mp4 or
* webm file as the output and at most one audio and/or one video elementary
- * stream.
+ * stream. MediaMuxer does not support muxing B-frames.
* <p>
* It is generally used like this:
*
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index c1805cb..7c6adad 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -72,7 +72,7 @@
/**
* Used as an int extra field to denote the page number to subscribe.
- * The value of {@code EXTRA_PAGE} should be greater than or equal to 1.
+ * The value of {@code EXTRA_PAGE} should be greater than or equal to 0.
*
* @see #EXTRA_PAGE_SIZE
*/
diff --git a/media/java/android/media/browse/MediaBrowserUtils.java b/media/java/android/media/browse/MediaBrowserUtils.java
index b06e598..2943e60 100644
--- a/media/java/android/media/browse/MediaBrowserUtils.java
+++ b/media/java/android/media/browse/MediaBrowserUtils.java
@@ -50,7 +50,7 @@
startIndex1 = 0;
endIndex1 = Integer.MAX_VALUE;
} else {
- startIndex1 = pageSize1 * (page1 - 1);
+ startIndex1 = pageSize1 * page1;
endIndex1 = startIndex1 + pageSize1 - 1;
}
@@ -58,7 +58,7 @@
startIndex2 = 0;
endIndex2 = Integer.MAX_VALUE;
} else {
- startIndex2 = pageSize2 * (page2 - 1);
+ startIndex2 = pageSize2 * page2;
endIndex2 = startIndex2 + pageSize2 - 1;
}
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index acf94f4c..03dc699 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -116,10 +116,10 @@
private final int mType;
private final boolean mIsHardwareInput;
- // TODO: Remove mLabel and mIconUri when createTvInputInfo() is removed.
- private String mLabel;
+ // TODO: Remove mIconUri when createTvInputInfo() is removed.
private Uri mIconUri;
+ private final CharSequence mLabel;
private final int mLabelResId;
private final Icon mIcon;
private final Icon mIconStandby;
@@ -161,8 +161,8 @@
TvInputInfo info = new TvInputInfo.Builder(context, service)
.setHdmiDeviceInfo(hdmiDeviceInfo)
.setParentId(parentId)
+ .setLabel(label)
.build();
- info.mLabel = label;
info.mIconUri = iconUri;
return info;
}
@@ -215,8 +215,8 @@
throws XmlPullParserException, IOException {
TvInputInfo info = new TvInputInfo.Builder(context, service)
.setTvInputHardwareInfo(hardwareInfo)
+ .setLabel(label)
.build();
- info.mLabel = label;
info.mIconUri = iconUri;
return info;
}
@@ -247,7 +247,7 @@
}
private TvInputInfo(ResolveInfo service, String id, int type, boolean isHardwareInput,
- int labelResId, Icon icon, Icon iconStandby, Icon iconDisconnected,
+ CharSequence label, int labelResId, Icon icon, Icon iconStandby, Icon iconDisconnected,
String setupActivity, String settingsActivity, boolean canRecord, int tunerCount,
HdmiDeviceInfo hdmiDeviceInfo, boolean isConnectedToHdmiSwitch, String parentId,
Bundle extras) {
@@ -255,6 +255,7 @@
mId = id;
mType = type;
mIsHardwareInput = isHardwareInput;
+ mLabel = label;
mLabelResId = labelResId;
mIcon = icon;
mIconStandby = iconStandby;
@@ -570,7 +571,7 @@
dest.writeString(mId);
dest.writeInt(mType);
dest.writeByte(mIsHardwareInput ? (byte) 1 : 0);
- dest.writeString(mLabel);
+ TextUtils.writeToParcel(mLabel, dest, flags);
dest.writeParcelable(mIconUri, flags);
dest.writeInt(mLabelResId);
dest.writeParcelable(mIcon, flags);
@@ -612,7 +613,7 @@
mId = in.readString();
mType = in.readInt();
mIsHardwareInput = in.readByte() == 1;
- mLabel = in.readString();
+ mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
mIconUri = in.readParcelable(null);
mLabelResId = in.readInt();
mIcon = in.readParcelable(null);
@@ -660,6 +661,7 @@
private final Context mContext;
private final ResolveInfo mResolveInfo;
+ private CharSequence mLabel;
private int mLabelResId;
private Icon mIcon;
private Icon mIconStandby;
@@ -746,12 +748,31 @@
/**
* Sets the label.
*
+ * @param label The text to be used as label.
+ * @return This Builder object to allow for chaining of calls to builder methods.
+ * @hide
+ */
+ @SystemApi
+ public Builder setLabel(CharSequence label) {
+ if (mLabelResId != 0) {
+ throw new IllegalStateException("Resource ID for label is already set.");
+ }
+ this.mLabel = label;
+ return this;
+ }
+
+ /**
+ * Sets the label.
+ *
* @param resId The resource ID of the text to use.
* @return This Builder object to allow for chaining of calls to builder methods.
* @hide
*/
@SystemApi
public Builder setLabel(int resId) {
+ if (mLabel != null) {
+ throw new IllegalStateException("Label text is already set.");
+ }
this.mLabelResId = resId;
return this;
}
@@ -868,8 +889,8 @@
type = TYPE_TUNER;
}
parseServiceMetadata(type);
- return new TvInputInfo(mResolveInfo, id, type, isHardwareInput, mLabelResId, mIcon,
- mIconStandby, mIconDisconnected, mSetupActivity, mSettingsActivity,
+ return new TvInputInfo(mResolveInfo, id, type, isHardwareInput, mLabel, mLabelResId,
+ mIcon, mIconStandby, mIconDisconnected, mSetupActivity, mSettingsActivity,
mCanRecord == null ? false : mCanRecord, mTunerCount == null ? 0 : mTunerCount,
mHdmiDeviceInfo, isConnectedToHdmiSwitch, mParentId, mExtras);
}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index c72a7a0..b4536b1 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -56,7 +56,26 @@
/**
* Central system API to the overall TV input framework (TIF) architecture, which arbitrates
- * interaction between applications and the selected TV inputs.
+ * interaction between applications and the selected TV inputs. You can retrieve an instance of
+ * this interface with {@link android.content.Context#getSystemService
+ * Context.getSystemService(Context.TV_INPUT_SERVICE)}.
+ *
+ * <p>There are three primary parties involved in the TV input framework (TIF) architecture:
+ *
+ * <ul>
+ * <li>The <strong>TV input manager</strong> as expressed by this class is the central point of the
+ * system that manages interaction between all other parts. It is expressed as the client-side API
+ * here which exists in each application context and communicates with a global system service that
+ * manages the interaction across all processes.
+ * <li>A <strong>TV input</strong> implemented by {@link TvInputService} represents an input source
+ * of TV, which can be a pass-through input such as HDMI, or a tuner input which provides broadcast
+ * TV programs. The system binds to the TV input per application’s request.
+ * on implementing TV inputs.
+ * <li><strong>Applications</strong> talk to the TV input manager to list TV inputs and check their
+ * status. Once an application find the input to use, it uses {@link TvView} or
+ * {@link TvRecordingClient} for further interaction such as watching and recording broadcast TV
+ * programs.
+ * </ul>
*/
public final class TvInputManager {
private static final String TAG = "TvInputManager";
@@ -824,11 +843,21 @@
/**
* Interface used to receive events from Hardware objects.
+ *
* @hide
*/
@SystemApi
public abstract static class HardwareCallback {
+ /**
+ * This is called when {@link Hardware} is no longer available for the client.
+ */
public abstract void onReleased();
+
+ /**
+ * This is called when the underlying {@link TvStreamConfig} has been changed.
+ *
+ * @param configs The new {@link TvStreamConfig}s.
+ */
public abstract void onStreamConfigChanged(TvStreamConfig[] configs);
}
@@ -1470,18 +1499,41 @@
}
/**
- * Returns acquired TvInputManager.Hardware object for given deviceId.
+ * Acquires {@link Hardware} object for the given device ID.
*
- * If there are other Hardware object acquired for the same deviceId, calling this method will
- * preempt the previously acquired object and report {@link HardwareCallback#onReleased} to the
- * old object.
+ * <p>A subsequent call to this method on the same {@code deviceId} will release the currently
+ * acquired Hardware.
+ *
+ * @param deviceId The device ID to acquire Hardware for.
+ * @param callback A callback to receive updates on Hardware.
+ * @param info The TV input which will use the acquired Hardware.
+ * @return Hardware on success, {@code null} otherwise.
+ *
+ * @removed
+ */
+ @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
+ public Hardware acquireTvInputHardware(int deviceId, final HardwareCallback callback,
+ TvInputInfo info) {
+ return acquireTvInputHardware(deviceId, info, callback);
+ }
+
+ /**
+ * Acquires {@link Hardware} object for the given device ID.
+ *
+ * <p>A subsequent call to this method on the same {@code deviceId} will release the currently
+ * acquired Hardware.
+ *
+ * @param deviceId The device ID to acquire Hardware for.
+ * @param callback A callback to receive updates on Hardware.
+ * @param info The TV input which will use the acquired Hardware.
+ * @return Hardware on success, {@code null} otherwise.
*
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
- public Hardware acquireTvInputHardware(int deviceId, final HardwareCallback callback,
- TvInputInfo info) {
+ public Hardware acquireTvInputHardware(int deviceId, TvInputInfo info,
+ final HardwareCallback callback) {
try {
return new Hardware(
mService.acquireTvInputHardware(deviceId, new ITvInputHardwareCallback.Stub() {
@@ -1503,6 +1555,9 @@
/**
* Releases previously acquired hardware object.
*
+ * @param deviceId The device ID this Hardware was acquired for
+ * @param hardware Hardware to release.
+ *
* @hide
*/
@SystemApi
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index ae86632..6954045 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -657,9 +657,9 @@
if (page == -1 && pageSize == -1) {
return list;
}
- int fromIndex = pageSize * (page - 1);
+ int fromIndex = pageSize * page;
int toIndex = fromIndex + pageSize;
- if (page < 1 || pageSize < 1 || fromIndex >= list.size()) {
+ if (page < 0 || pageSize < 1 || fromIndex >= list.size()) {
return Collections.EMPTY_LIST;
}
if (toIndex > list.size()) {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
index dde9bda..312d9aa 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
@@ -61,7 +61,7 @@
private static final String[] EXIF_TAGS = {
ExifInterface.TAG_MAKE,
ExifInterface.TAG_MODEL,
- ExifInterface.TAG_APERTURE,
+ ExifInterface.TAG_F_NUMBER,
ExifInterface.TAG_DATETIME,
ExifInterface.TAG_EXPOSURE_TIME,
ExifInterface.TAG_FLASH,
@@ -77,7 +77,7 @@
ExifInterface.TAG_GPS_TIMESTAMP,
ExifInterface.TAG_IMAGE_LENGTH,
ExifInterface.TAG_IMAGE_WIDTH,
- ExifInterface.TAG_ISO,
+ ExifInterface.TAG_ISO_SPEED_RATINGS,
ExifInterface.TAG_ORIENTATION,
ExifInterface.TAG_WHITE_BALANCE
};
@@ -288,7 +288,7 @@
// Checks values.
assertStringTag(exifInterface, ExifInterface.TAG_MAKE, expectedValue.make);
assertStringTag(exifInterface, ExifInterface.TAG_MODEL, expectedValue.model);
- assertFloatTag(exifInterface, ExifInterface.TAG_APERTURE, expectedValue.aperture);
+ assertFloatTag(exifInterface, ExifInterface.TAG_F_NUMBER, expectedValue.aperture);
assertStringTag(exifInterface, ExifInterface.TAG_DATETIME, expectedValue.datetime);
assertFloatTag(exifInterface, ExifInterface.TAG_EXPOSURE_TIME, expectedValue.exposureTime);
assertFloatTag(exifInterface, ExifInterface.TAG_FLASH, expectedValue.flash);
@@ -308,7 +308,7 @@
assertStringTag(exifInterface, ExifInterface.TAG_GPS_TIMESTAMP, expectedValue.gpsTimestamp);
assertIntTag(exifInterface, ExifInterface.TAG_IMAGE_LENGTH, expectedValue.imageLength);
assertIntTag(exifInterface, ExifInterface.TAG_IMAGE_WIDTH, expectedValue.imageWidth);
- assertStringTag(exifInterface, ExifInterface.TAG_ISO, expectedValue.iso);
+ assertStringTag(exifInterface, ExifInterface.TAG_ISO_SPEED_RATINGS, expectedValue.iso);
assertIntTag(exifInterface, ExifInterface.TAG_ORIENTATION, expectedValue.orientation);
assertIntTag(exifInterface, ExifInterface.TAG_WHITE_BALANCE, expectedValue.whiteBalance);
}
diff --git a/packages/CtsShim/Android.mk b/packages/CtsShim/Android.mk
new file mode 100644
index 0000000..537b171
--- /dev/null
+++ b/packages/CtsShim/Android.mk
@@ -0,0 +1,61 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+###########################################################
+# Variant: Privileged app
+
+include $(CLEAR_VARS)
+# this needs to be a privileged application
+LOCAL_PRIVILEGED_MODULE := true
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_SDK_VERSION := current
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PACKAGE_NAME := CtsShimPriv
+
+#TODO need to find the correct certificate
+#Change in conjunction with cts/hostsidetests/appsecurity/test-apps/IntentFilterApp
+LOCAL_CERTIFICATE := platform
+LOCAL_MANIFEST_FILE := priv_shim/AndroidManifest.xml
+
+include $(BUILD_PACKAGE)
+
+
+
+###########################################################
+# Variant: System app
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_SDK_VERSION := current
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PACKAGE_NAME := CtsShim
+
+#TODO need to find the correct certificate
+#Change in conjunction with cts/hostsidetests/appsecurity/test-apps/IntentFilterApp
+LOCAL_CERTIFICATE := platform
+LOCAL_MANIFEST_FILE := shim/AndroidManifest.xml
+
+include $(BUILD_PACKAGE)
+
+
diff --git a/packages/CtsShim/priv_shim/AndroidManifest.xml b/packages/CtsShim/priv_shim/AndroidManifest.xml
new file mode 100644
index 0000000..0a3f823
--- /dev/null
+++ b/packages/CtsShim/priv_shim/AndroidManifest.xml
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<!-- Manifest for the privileged CTS shim -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.priv.ctsshim">
+ <application android:label="CtsShim">
+
+ <!-- These activities don't actually exist; define them just to test the filters !-->
+
+ <!-- install test; [some] high priority filters granted -->
+ <activity android:name=".InstallPriority">
+ <!-- normal actions; priority will be granted -->
+ <intent-filter android:priority="100">
+ <action android:name="android.intent.action.SEARCH" />
+ <category android:name="android.intent.category.INFO" />
+ </intent-filter>
+
+ <!-- protected actions; priority will be denied -->
+ <intent-filter android:priority="100">
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ </intent-filter>
+ <intent-filter android:priority="100">
+ <action android:name="android.intent.action.SEND" />
+ </intent-filter>
+ <intent-filter android:priority="100">
+ <action android:name="android.intent.action.SEND_MULTIPLE" />
+ </intent-filter>
+ <intent-filter android:priority="100">
+ <action android:name="android.intent.action.SENDTO" />
+ </intent-filter>
+ </activity>
+
+ <!-- upgrade test; single, equivalent filter -->
+ <activity android:name=".UpgradeMatch">
+ <intent-filter android:priority="100">
+ <action android:name="com.android.cts.action.MATCH" />
+ <category android:name="android.intent.category.INFO" />
+ </intent-filter>
+ </activity>
+
+ <!-- upgrade test; multiple, equivalent filters -->
+ <activity android:name=".UpgradeMatchMultiple">
+ <intent-filter android:priority="100">
+ <action android:name="com.android.cts.action.MATCH_MULTIPLE" />
+ <category android:name="android.intent.category.INFO" />
+ </intent-filter>
+
+ <intent-filter android:priority="150">
+ <action android:name="com.android.cts.action.MATCH_MULTIPLE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="http" />
+ <data android:scheme="https" />
+ <data android:host="www.google.com" android:port="80" />
+ <data android:host="www.google.com" android:port="8080" />
+ <data android:host="goo.gl" android:port="443" />
+ </intent-filter>
+ </activity>
+
+ <!-- upgrade test; lower priority -->
+ <activity android:name=".UpgradeLowerPriority">
+ <intent-filter android:priority="100">
+ <action android:name="com.android.cts.action.LOWER_PRIORITY" />
+ <category android:name="android.intent.category.INFO" />
+ </intent-filter>
+ </activity>
+
+ <!-- upgrade test; action subset -->
+ <activity android:name=".UpgradeActionSubset">
+ <intent-filter android:priority="100">
+ <action android:name="com.android.cts.action.ACTION_SUB" />
+ <action android:name="com.android.cts.action.ACTION_SUB_2" />
+ <action android:name="com.android.cts.action.ACTION_SUB_3" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <!-- upgrade test; category subset -->
+ <activity android:name=".UpgradeCategorySubset">
+ <intent-filter android:priority="100">
+ <action android:name="com.android.cts.action.CATEGORY_SUB" />
+ <category android:name="android.intent.category.INFO" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <!-- upgrade test; scheme subset -->
+ <activity android:name=".UpgradeSchemeSubset">
+ <intent-filter android:priority="100">
+ <action android:name="com.android.cts.action.SCHEME_SUB" />
+ <data android:scheme="content" />
+ <data android:scheme="flubber" />
+ <data android:scheme="zoodle" />
+ </intent-filter>
+ </activity>
+
+ <!-- upgrade test; authority subset -->
+ <activity android:name=".UpgradeAuthoritySubset">
+ <intent-filter android:priority="100">
+ <action android:name="com.android.cts.action.AUTHORITY_SUB" />
+ <data android:host="www.google.com" android:port="80" />
+ <data android:host="www.google.com" android:port="8080" />
+ <data android:host="mail.google.com" android:port="80" />
+ <data android:host="goo.gl" android:port="443" />
+ </intent-filter>
+ </activity>
+
+
+ <!-- upgrade test; new action -->
+ <activity android:name=".UpgradeNewAction">
+ <intent-filter android:priority="100">
+ <action android:name="com.android.cts.action.NEW_ACTION" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <!-- upgrade test; new category -->
+ <activity android:name=".UpgradeNewCategory">
+ <intent-filter android:priority="100">
+ <action android:name="com.android.cts.action.NEW_CATEGORY" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <!-- upgrade test; new scheme -->
+ <activity android:name=".UpgradeNewScheme">
+ <intent-filter android:priority="100">
+ <action android:name="com.android.cts.action.NEW_SCHEME" />
+ <data android:scheme="content" />
+ </intent-filter>
+ </activity>
+
+ <!-- upgrade test; new authority -->
+ <activity android:name=".UpgradeNewAuthority">
+ <intent-filter android:priority="100">
+ <action android:name="com.android.cts.action.NEW_AUTHORITY" />
+ <data android:host="www.google.com" android:port="80" />
+ </intent-filter>
+ </activity>
+
+ </application>
+</manifest>
+
diff --git a/packages/CtsShim/shim/AndroidManifest.xml b/packages/CtsShim/shim/AndroidManifest.xml
new file mode 100644
index 0000000..ee4b547
--- /dev/null
+++ b/packages/CtsShim/shim/AndroidManifest.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<!-- Manifest for the system CTS shim -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.system.ctsshim">
+ <application android:label="CtsShim">
+
+ <!-- These activities don't actually exist; define them just to test the filters !-->
+
+ <!-- install test; high priority filter DENIED -->
+ <activity android:name=".InstallPriority">
+ <intent-filter android:priority="100">
+ <action android:name="android.intent.action.SEARCH" />
+ <category android:name="android.intent.category.INFO" />
+ </intent-filter>
+ <intent-filter android:priority="100">
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ </intent-filter>
+ <intent-filter android:priority="100">
+ <action android:name="android.intent.action.SEND" />
+ </intent-filter>
+ <intent-filter android:priority="100">
+ <action android:name="android.intent.action.SEND_MULTIPLE" />
+ </intent-filter>
+ <intent-filter android:priority="100">
+ <action android:name="android.intent.action.SENDTO" />
+ </intent-filter>
+ </activity>
+
+ </application>
+</manifest>
+
diff --git a/packages/DocumentsUI/app-perf-tests/AndroidManifest.xml b/packages/DocumentsUI/app-perf-tests/AndroidManifest.xml
index 1c3ed80..0013b6b 100644
--- a/packages/DocumentsUI/app-perf-tests/AndroidManifest.xml
+++ b/packages/DocumentsUI/app-perf-tests/AndroidManifest.xml
@@ -2,6 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.documentsui.appperftests">
+ <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
+
<application>
<uses-library android:name="android.test.runner" />
diff --git a/packages/DocumentsUI/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java b/packages/DocumentsUI/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java
index d6e8a96..ce2fc13 100644
--- a/packages/DocumentsUI/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java
+++ b/packages/DocumentsUI/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java
@@ -17,6 +17,8 @@
package com.android.documentsui;
import android.app.Activity;
+import android.app.ActivityManager;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -91,12 +93,15 @@
}
private void killProviders() throws Exception {
- final PackageManager pm = getInstrumentation().getContext().getPackageManager();
+ final Context context = getInstrumentation().getContext();
+ final PackageManager pm = context.getPackageManager();
+ final ActivityManager am = (ActivityManager) context.getSystemService(
+ Context.ACTIVITY_SERVICE);
final Intent intent = new Intent(DocumentsContract.PROVIDER_INTERFACE);
final List<ResolveInfo> providers = pm.queryIntentContentProviders(intent, 0);
for (ResolveInfo info : providers) {
final String packageName = info.providerInfo.packageName;
- mDevice.executeShellCommand("am force-stop " + packageName);
+ am.killBackgroundProcesses(packageName);
}
}
}
diff --git a/packages/DocumentsUI/res/values-af/strings.xml b/packages/DocumentsUI/res/values-af/strings.xml
index 75d9b4b..1a7c620 100644
--- a/packages/DocumentsUI/res/values-af/strings.xml
+++ b/packages/DocumentsUI/res/values-af/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Kon nie dokument hernoem nie"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sommige lêers is omgeskakel"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Gee <xliff:g id="APPNAME"><b>^1</b></xliff:g> toegang tot <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>-gids op <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Gee <xliff:g id="APPNAME"><b>^1</b></xliff:g> toegang tot <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>-gids?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Gee <xliff:g id="APPNAME"><b>^1</b></xliff:g> toegang tot jou data, insluitend foto\'s en video\'s, op <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Moenie weer vra nie"</string>
<string name="allow" msgid="7225948811296386551">"Laat toe"</string>
diff --git a/packages/DocumentsUI/res/values-am/strings.xml b/packages/DocumentsUI/res/values-am/strings.xml
index 922b9ca..ca43dab 100644
--- a/packages/DocumentsUI/res/values-am/strings.xml
+++ b/packages/DocumentsUI/res/values-am/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"ሰነዱን ዳግም መሰየም አልተሳካም"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"አንዳንድ ፋይሎች ተለውጠዋል"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> በ<xliff:g id="STORAGE"><i>^3</i></xliff:g> ላይ የ<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ማውጫ መደረሻ ይሰጠው?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"የ<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ማውጫ መዳረሻ ለ<xliff:g id="APPNAME"><b>^1</b></xliff:g> ይሰጠው?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"በ<xliff:g id="STORAGE"><i>^2</i></xliff:g> ላይ ያሉትን ፎቶዎች እና ቪዲዮዎች ጨምሮ የውሂብዎ መዳረሻ ለ<xliff:g id="APPNAME"><b>^1</b></xliff:g> ይሰጥ?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"ዳግም አትጠይቅ"</string>
<string name="allow" msgid="7225948811296386551">"ይፍቀዱ"</string>
diff --git a/packages/DocumentsUI/res/values-ar/strings.xml b/packages/DocumentsUI/res/values-ar/strings.xml
index f48c542..e6fac50 100644
--- a/packages/DocumentsUI/res/values-ar/strings.xml
+++ b/packages/DocumentsUI/res/values-ar/strings.xml
@@ -139,6 +139,7 @@
<string name="rename_error" msgid="4203041674883412606">"أخفقت إعادة تسمية المستند."</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"تم تحويل بعض الملفات"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"هل تريد منح التطبيق <xliff:g id="APPNAME"><b>^1</b></xliff:g> حق الوصول إلى الدليل <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> على <xliff:g id="STORAGE"><i>^3</i></xliff:g>؟"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"هل تريد تمكين <xliff:g id="APPNAME"><b>^1</b></xliff:g> من الدخول إلى دليل <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>؟"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"هل تريد منح <xliff:g id="APPNAME"><b>^1</b></xliff:g> حق الوصول إلى بياناتك، بما في ذلك الصور ومقاطع الفيديو على <xliff:g id="STORAGE"><i>^2</i></xliff:g>؟"</string>
<string name="never_ask_again" msgid="4295278542972859268">"عدم السؤال مرة أخرى"</string>
<string name="allow" msgid="7225948811296386551">"السماح"</string>
diff --git a/packages/DocumentsUI/res/values-az-rAZ/strings.xml b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
index a4d6f51..75a0686 100644
--- a/packages/DocumentsUI/res/values-az-rAZ/strings.xml
+++ b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Sənəd adını dəyişmək uğursuz oldu"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Bəzi fayllar konvertasiya edilib"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g> yaddaşında <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> kataloquna <xliff:g id="APPNAME"><b>^1</b></xliff:g> girişi təqdim edilsin?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> kataloquna <xliff:g id="APPNAME"><b>^1</b></xliff:g> girişi təqdim edilsin?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g> yaddaşında foto və videolar daxil olmaqla datanıza <xliff:g id="APPNAME"><b>^1</b></xliff:g> girişi təmin edilsin?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Bir daha soruşmayın"</string>
<string name="allow" msgid="7225948811296386551">"İcazə verin"</string>
diff --git a/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
index 2c4fe5c..34c08bd 100644
--- a/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
@@ -118,6 +118,7 @@
<string name="rename_error" msgid="4203041674883412606">"Preimenovanje dokumenta nije uspelo"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Neke datoteke su konvertovane"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Želite li da aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> odobrite pristup direktorijumu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> na memorijskom prostoru <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Želite da dozvolite da <xliff:g id="APPNAME"><b>^1</b></xliff:g> pristupa direktorijumu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Želite da li da dozvolite da aplikacija <xliff:g id="APPNAME"><b>^1</b></xliff:g> pristupa podacima, uključujući slike i video snimke, na lokaciji <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Ne pitaj ponovo"</string>
<string name="allow" msgid="7225948811296386551">"Dozvoli"</string>
diff --git a/packages/DocumentsUI/res/values-be-rBY/strings.xml b/packages/DocumentsUI/res/values-be-rBY/strings.xml
index 6e4113e..8493c477 100644
--- a/packages/DocumentsUI/res/values-be-rBY/strings.xml
+++ b/packages/DocumentsUI/res/values-be-rBY/strings.xml
@@ -125,6 +125,7 @@
<string name="rename_error" msgid="4203041674883412606">"Не атрымалася перайменаваць дакумент"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Некаторыя файлы былі сканвертаваныя"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Даць праграме <xliff:g id="APPNAME"><b>^1</b></xliff:g> доступ да дырэкторыі <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> у <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Даць праграме <xliff:g id="APPNAME"><b>^1</b></xliff:g> доступ да дырэкторыі <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Даць <xliff:g id="APPNAME"><b>^1</b></xliff:g> доступ да вашых даных, у тым ліку фатаграфій і відэа, на <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Больш не пытацца"</string>
<string name="allow" msgid="7225948811296386551">"Дазволіць"</string>
diff --git a/packages/DocumentsUI/res/values-bg/strings.xml b/packages/DocumentsUI/res/values-bg/strings.xml
index 4b24a0e..1914bf5 100644
--- a/packages/DocumentsUI/res/values-bg/strings.xml
+++ b/packages/DocumentsUI/res/values-bg/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Преименуването на документа не бе успешно"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Някои файлове бяха преобразувани"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Да се предостави ли на <xliff:g id="APPNAME"><b>^1</b></xliff:g> достъп до директорията „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“ в/ъв <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Да се предостави ли на <xliff:g id="APPNAME"><b>^1</b></xliff:g> достъп до директорията „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Да се предостави ли на <xliff:g id="APPNAME"><b>^1</b></xliff:g> достъп до данните ви в хранилището (<xliff:g id="STORAGE"><i>^2</i></xliff:g>), включително снимки и видеоклипове?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Без повторно питане"</string>
<string name="allow" msgid="7225948811296386551">"Разрешаване"</string>
diff --git a/packages/DocumentsUI/res/values-bn-rBD/strings.xml b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
index 79cd382..d931c2b 100644
--- a/packages/DocumentsUI/res/values-bn-rBD/strings.xml
+++ b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"দস্তাবেজের পুনঃনামকরণ ব্যর্থ হয়েছে৷"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"কিছু ফাইল রূপান্তরিত হয়েছে"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> কে <xliff:g id="STORAGE"><i>^3</i></xliff:g> এ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> সংগ্রহ অ্যাক্সেস করার মঞ্জুরি দিতে চান?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> কে <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> সংগ্রহ অ্যাক্সেস করার অনুমতি দেবেন?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g> এ থাকা ফটো ও ভিডিওগুলি সমেত <xliff:g id="APPNAME"><b>^1</b></xliff:g> কে আপনার ডেটা অ্যাক্সেস করার অনুমতি দেবেন?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"আর জিজ্ঞাসা করবেন না"</string>
<string name="allow" msgid="7225948811296386551">"অনুমতি দিন"</string>
diff --git a/packages/DocumentsUI/res/values-bs-rBA/strings.xml b/packages/DocumentsUI/res/values-bs-rBA/strings.xml
index 14d6716..47ff436 100644
--- a/packages/DocumentsUI/res/values-bs-rBA/strings.xml
+++ b/packages/DocumentsUI/res/values-bs-rBA/strings.xml
@@ -118,6 +118,7 @@
<string name="rename_error" msgid="4203041674883412606">"Nije uspjelo preimenovanje dokumenta"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Neke od datoteka su pretvorene"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Omogućiti <xliff:g id="APPNAME"><b>^1</b></xliff:g> pristup direktoriju <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> sa <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Odobriti aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> pristup direktoriju <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Želite li odobriti aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> pristup svojim podacima, uključujući fotografije i video zapise, na <xliff:g id="STORAGE"><i>^2</i></xliff:g> ?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Ne pitaj ponovo"</string>
<string name="allow" msgid="7225948811296386551">"Dozvoli"</string>
diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml
index 73998b1..09af97d 100644
--- a/packages/DocumentsUI/res/values-ca/strings.xml
+++ b/packages/DocumentsUI/res/values-ca/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"No s\'ha pogut canviar el nom del document"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"S\'han convertit alguns fitxers"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Vols que l\'aplicació <xliff:g id="APPNAME"><b>^1</b></xliff:g> tingui accés al directori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> de l\'emmagatzematge <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Vols que l\'aplicació <xliff:g id="APPNAME"><b>^1</b></xliff:g> tingui accés al directori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Vols que l\'aplicació <xliff:g id="APPNAME"><b>^1</b></xliff:g> tingui accés a les dades de <xliff:g id="STORAGE"><i>^2</i></xliff:g>, incloses les fotos i els vídeos?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"No m\'ho demanis més"</string>
<string name="allow" msgid="7225948811296386551">"Permet"</string>
diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml
index ffabe77..cba2e0e 100644
--- a/packages/DocumentsUI/res/values-cs/strings.xml
+++ b/packages/DocumentsUI/res/values-cs/strings.xml
@@ -125,6 +125,7 @@
<string name="rename_error" msgid="4203041674883412606">"Dokument se nepodařilo přejmenovat."</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Některé soubory byly převedeny"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Chcete aplikaci <xliff:g id="APPNAME"><b>^1</b></xliff:g> udělit přístup k adresáři <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> v úložišti <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Chcete aplikaci <xliff:g id="APPNAME"><b>^1</b></xliff:g> udělit přístup k adresáři <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Chcete aplikaci <xliff:g id="APPNAME"><b>^1</b></xliff:g> udělit přístup ke svým datům v úložišti <xliff:g id="STORAGE"><i>^2</i></xliff:g>, včetně fotek a videí?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Příště se neptat"</string>
<string name="allow" msgid="7225948811296386551">"Povolit"</string>
diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml
index bf328ab..f048e34 100644
--- a/packages/DocumentsUI/res/values-da/strings.xml
+++ b/packages/DocumentsUI/res/values-da/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Dokumentet kunne ikke omdøbes"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Nogle filer er konverteret"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Vil du give <xliff:g id="APPNAME"><b>^1</b></xliff:g> adgang til mappen <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> på <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Vil du give <xliff:g id="APPNAME"><b>^1</b></xliff:g> adgang til indekset <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Vil du give <xliff:g id="APPNAME"><b>^1</b></xliff:g> adgang til dine data, herunder billeder og videoer på <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Spørg ikke igen"</string>
<string name="allow" msgid="7225948811296386551">"Tillad"</string>
diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml
index 9ccb564..a6eae70 100644
--- a/packages/DocumentsUI/res/values-de/strings.xml
+++ b/packages/DocumentsUI/res/values-de/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Dokument konnte nicht umbenannt werden"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Einige Dateien wurden konvertiert"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> Zugriff auf das Verzeichnis <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> auf <xliff:g id="STORAGE"><i>^3</i></xliff:g> geben?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Möchtest du <xliff:g id="APPNAME"><b>^1</b></xliff:g> Zugriff auf das Verzeichnis <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> geben?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Möchtest du <xliff:g id="APPNAME"><b>^1</b></xliff:g> Zugriff auf deine Daten auf <xliff:g id="STORAGE"><i>^2</i></xliff:g> geben, einschließlich Fotos und Videos?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Nicht mehr fragen"</string>
<string name="allow" msgid="7225948811296386551">"Zulassen"</string>
diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml
index f23a35d..7dc2067 100644
--- a/packages/DocumentsUI/res/values-el/strings.xml
+++ b/packages/DocumentsUI/res/values-el/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Αποτυχία μετονομασίας εγγράφου"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Ορισμένα αρχεία μετατράπηκαν"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Να εκχωρηθεί στην εφαρμογή <xliff:g id="APPNAME"><b>^1</b></xliff:g> πρόσβαση στον κατάλογο <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> στον αποθηκευτικό χώρο <xliff:g id="STORAGE"><i>^3</i></xliff:g>;"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Εκχώρηση πρόσβασης στην εφαρμογή <xliff:g id="APPNAME"><b>^1</b></xliff:g> στον κατάλογο <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>;"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Θέλετε να εκχωρήσετε πρόσβαση στα δεδομένα σας στην εφαρμογή <xliff:g id="APPNAME"><b>^1</b></xliff:g>, συμπεριλαμβανομένων των φωτογραφιών και των βίντεό σας, στον αποθηκευτικό χώρο <xliff:g id="STORAGE"><i>^2</i></xliff:g>;"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Να μην ερωτηθώ ξανά"</string>
<string name="allow" msgid="7225948811296386551">"Να επιτρέπεται"</string>
diff --git a/packages/DocumentsUI/res/values-en-rAU/strings.xml b/packages/DocumentsUI/res/values-en-rAU/strings.xml
index f82f988..8524de5 100644
--- a/packages/DocumentsUI/res/values-en-rAU/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rAU/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Failed to rename document"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Some files were converted"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory on <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to your data, including photos and videos, on <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Don\'t ask again"</string>
<string name="allow" msgid="7225948811296386551">"Allow"</string>
diff --git a/packages/DocumentsUI/res/values-en-rGB/strings.xml b/packages/DocumentsUI/res/values-en-rGB/strings.xml
index f82f988..8524de5 100644
--- a/packages/DocumentsUI/res/values-en-rGB/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rGB/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Failed to rename document"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Some files were converted"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory on <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to your data, including photos and videos, on <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Don\'t ask again"</string>
<string name="allow" msgid="7225948811296386551">"Allow"</string>
diff --git a/packages/DocumentsUI/res/values-en-rIN/strings.xml b/packages/DocumentsUI/res/values-en-rIN/strings.xml
index f82f988..8524de5 100644
--- a/packages/DocumentsUI/res/values-en-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rIN/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Failed to rename document"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Some files were converted"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory on <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to your data, including photos and videos, on <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Don\'t ask again"</string>
<string name="allow" msgid="7225948811296386551">"Allow"</string>
diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml
index 5c823d0..87641a7 100644
--- a/packages/DocumentsUI/res/values-es-rUS/strings.xml
+++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"No se pudo cambiar el nombre del documento"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Se convirtieron algunos archivos"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"¿Otorgar acceso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> al directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> en <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"¿Quieres otorgar acceso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> al directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"¿Quieres otorgar acceso a la app de <xliff:g id="APPNAME"><b>^1</b></xliff:g> a tus datos, incluidas tus fotos y videos en <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"No volver a preguntar"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
diff --git a/packages/DocumentsUI/res/values-es/strings.xml b/packages/DocumentsUI/res/values-es/strings.xml
index 60d1d1c..9054561 100644
--- a/packages/DocumentsUI/res/values-es/strings.xml
+++ b/packages/DocumentsUI/res/values-es/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Error al cambiar el nombre del documento"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Se han convertido algunos archivos"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"¿Permitir que <xliff:g id="APPNAME"><b>^1</b></xliff:g> acceda al directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> (<xliff:g id="STORAGE"><i>^3</i></xliff:g>)?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"¿Permitir que <xliff:g id="APPNAME"><b>^1</b></xliff:g> acceda al directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"¿Permitir que <xliff:g id="APPNAME"><b>^1</b></xliff:g> acceda a tus datos, incluidos los vídeos y las fotos, de <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"No volver a preguntar"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
diff --git a/packages/DocumentsUI/res/values-et-rEE/strings.xml b/packages/DocumentsUI/res/values-et-rEE/strings.xml
index 0fdc435..4bb2a9b 100644
--- a/packages/DocumentsUI/res/values-et-rEE/strings.xml
+++ b/packages/DocumentsUI/res/values-et-rEE/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Dokumendi ümbernimetamine ebaõnnestus"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Mõned failid teisendati"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Kas anda rakendusele <xliff:g id="APPNAME"><b>^1</b></xliff:g> juurdepääs kataloogile <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> salvestusruumis <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Kas anda rakendusele <xliff:g id="APPNAME"><b>^1</b></xliff:g> juurdepääs kataloogile <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Kas anda rakendusele <xliff:g id="APPNAME"><b>^1</b></xliff:g> juurdepääs teie andmetele (sh fotod ja videod) salvestusruumis <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Ära enam küsi"</string>
<string name="allow" msgid="7225948811296386551">"Luba"</string>
diff --git a/packages/DocumentsUI/res/values-eu-rES/strings.xml b/packages/DocumentsUI/res/values-eu-rES/strings.xml
index b54e542..d2bf89d 100644
--- a/packages/DocumentsUI/res/values-eu-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-eu-rES/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Ezin izan zaio aldatu izena dokumentuari"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Artxibo batzuk bihurtu dira"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> aplikazioari <xliff:g id="STORAGE"><i>^3</i></xliff:g> unitateko <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> direktorioa atzitzeko baimena eman nahi diozu?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> aplikazioari <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> direktoriorako sarbidea eman nahi diozu?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> aplikazioari zure datuak atzitzea baimendu nahi diozu, besteak beste, <xliff:g id="STORAGE"><i>^2</i></xliff:g> biltegian dituzun argazkiak eta bideoak?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Ez galdetu berriro"</string>
<string name="allow" msgid="7225948811296386551">"Onartu"</string>
diff --git a/packages/DocumentsUI/res/values-fa/strings.xml b/packages/DocumentsUI/res/values-fa/strings.xml
index cc7eeb5..1a4c035 100644
--- a/packages/DocumentsUI/res/values-fa/strings.xml
+++ b/packages/DocumentsUI/res/values-fa/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"نام سند تغییر نکرد"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"بعضی از فایلها تبدیل شدند"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"به <xliff:g id="APPNAME"><b>^1</b></xliff:g> اجازه داده شود به فهرست راهنمای <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> در <xliff:g id="STORAGE"><i>^3</i></xliff:g> دسترسی داشته باشد؟"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"به <xliff:g id="APPNAME"><b>^1</b></xliff:g> اجازه دسترسی به دایرکتوری <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> داده شود؟"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"به <xliff:g id="APPNAME"><b>^1</b></xliff:g> اجازه میدهید به دادههایتان دسترسی پیدا کند، از جمله عکسها و ویدیوهایتان در <xliff:g id="STORAGE"><i>^2</i></xliff:g>؟"</string>
<string name="never_ask_again" msgid="4295278542972859268">"دوباره سؤال نشود"</string>
<string name="allow" msgid="7225948811296386551">"ارزیابیشده"</string>
diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml
index 17e4d75..dfcfe89 100644
--- a/packages/DocumentsUI/res/values-fi/strings.xml
+++ b/packages/DocumentsUI/res/values-fi/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Dokumentin nimen muuttaminen epäonnistui."</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Joitakin tiedostoja muunnettiin."</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Myönnetäänkö sovellukselle <xliff:g id="APPNAME"><b>^1</b></xliff:g> sijainnissa <xliff:g id="STORAGE"><i>^3</i></xliff:g> olevan hakemiston <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> käyttöoikeus?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Saako <xliff:g id="APPNAME"><b>^1</b></xliff:g> käyttää hakemistoa <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Myönnetäänkö sovellukselle <xliff:g id="APPNAME"><b>^1</b></xliff:g> sijainnissa <xliff:g id="STORAGE"><i>^2</i></xliff:g> olevien tietojesi, mukaan lukien valokuviesi ja videoidesi, käyttöoikeus?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Älä kysy uudestaan"</string>
<string name="allow" msgid="7225948811296386551">"Salli"</string>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
index 5dbf5ebe..543e226 100644
--- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml
+++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Impossible de renommer le document"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Certains fichiers ont été convertis"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Accorder à <xliff:g id="APPNAME"><b>^1</b></xliff:g> l\'accès au répertoire <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> sur <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Accorder à <xliff:g id="APPNAME"><b>^1</b></xliff:g> l\'accès au répertoire <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Voulez-vous accorder l\'accès à vos données à <xliff:g id="APPNAME"><b>^1</b></xliff:g>, y compris vos photos et vos vidéos, sur <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Ne plus me demander"</string>
<string name="allow" msgid="7225948811296386551">"Autoriser"</string>
diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml
index 127d0da..05716d7 100644
--- a/packages/DocumentsUI/res/values-fr/strings.xml
+++ b/packages/DocumentsUI/res/values-fr/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Échec du changement de nom du document."</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Certains fichiers ont été convertis"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Autoriser <xliff:g id="APPNAME"><b>^1</b></xliff:g> à accéder à l\'annuaire \"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>\" sur <xliff:g id="STORAGE"><i>^3</i></xliff:g> ?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Autoriser <xliff:g id="APPNAME"><b>^1</b></xliff:g> à accéder à l\'annuaire \"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>\" ?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Autoriser <xliff:g id="APPNAME"><b>^1</b></xliff:g> à accéder à vos données, y compris les photos et les vidéos, sur <xliff:g id="STORAGE"><i>^2</i></xliff:g> ?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Ne plus demander"</string>
<string name="allow" msgid="7225948811296386551">"Autoriser"</string>
diff --git a/packages/DocumentsUI/res/values-gl-rES/strings.xml b/packages/DocumentsUI/res/values-gl-rES/strings.xml
index 4cce3c9..5797a96 100644
--- a/packages/DocumentsUI/res/values-gl-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-gl-rES/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Non se puido cambiar o nome do documento"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Convertéronse algúns ficheiros"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Queres outorgar acceso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> ao directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> no almacenamento de <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Queres darlle acceso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> ao directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Queres darlle acceso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> aos teus datos almacenados en <xliff:g id="STORAGE"><i>^2</i></xliff:g>, incluídos vídeos e fotos?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Non preguntar de novo"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
diff --git a/packages/DocumentsUI/res/values-gu-rIN/strings.xml b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
index 1db54f9..48e43c4 100644
--- a/packages/DocumentsUI/res/values-gu-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"દસ્તાવેજનું નામ બદલવામાં નિષ્ફળ થયાં"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"કેટલીક ફાઇલો રૂપાંતરિત કરી હતી"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ને <xliff:g id="STORAGE"><i>^3</i></xliff:g> પર <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> નિર્દેશિકાની ઍક્સેસ આપીએ?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ને <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> નિર્દેશિકાની ઍક્સેસ આપીએ?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ને <xliff:g id="STORAGE"><i>^2</i></xliff:g> પર ફોટા અને વિડિઓઝ સહિત તમારા ડેટાની અૅક્સેસ આપીએ?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"ફરીથી પૂછશો નહીં"</string>
<string name="allow" msgid="7225948811296386551">"મંજૂરી આપો"</string>
diff --git a/packages/DocumentsUI/res/values-hi/strings.xml b/packages/DocumentsUI/res/values-hi/strings.xml
index de1e25e..fa82ee8 100644
--- a/packages/DocumentsUI/res/values-hi/strings.xml
+++ b/packages/DocumentsUI/res/values-hi/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"दस्तावेज़ का नाम बदलना विफल रहा"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"कुछ फ़ाइलें रूपांतरित हो गई थीं"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> को <xliff:g id="STORAGE"><i>^3</i></xliff:g> पर <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिका का एक्सेस दें?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> को <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिका का एक्सेस प्रदान करें?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> को <xliff:g id="STORAGE"><i>^2</i></xliff:g> पर मौजूद फ़ोटो और वीडियो सहित, अपने डेटा का एक्सेस प्रदान करें?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"फिर से ना पूछें"</string>
<string name="allow" msgid="7225948811296386551">"अनुमति दें"</string>
diff --git a/packages/DocumentsUI/res/values-hr/strings.xml b/packages/DocumentsUI/res/values-hr/strings.xml
index bf91c6a..7988c71 100644
--- a/packages/DocumentsUI/res/values-hr/strings.xml
+++ b/packages/DocumentsUI/res/values-hr/strings.xml
@@ -118,6 +118,7 @@
<string name="rename_error" msgid="4203041674883412606">"Naziv dokumenta nije promijenjen"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Neke su datoteke konvertirane"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Želite li aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> odobriti pristup direktoriju <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> na pohrani <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Želite li aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> odobriti da pristupa direktoriju <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Želite li aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> dopustiti pristup podacima, uključujući fotografije i videozapise na vanjskoj pohrani (<xliff:g id="STORAGE"><i>^2</i></xliff:g>)?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Više me ne pitaj"</string>
<string name="allow" msgid="7225948811296386551">"Dopusti"</string>
diff --git a/packages/DocumentsUI/res/values-hu/strings.xml b/packages/DocumentsUI/res/values-hu/strings.xml
index f955318..fb666b5 100644
--- a/packages/DocumentsUI/res/values-hu/strings.xml
+++ b/packages/DocumentsUI/res/values-hu/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Nem sikerült átnevezni a dokumentumot"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Egyes fájlokat konvertált a rendszer"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Hozzáférést biztosít a(z) <xliff:g id="APPNAME"><b>^1</b></xliff:g> számára a(z) <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> könyvtárhoz itt: <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Hozzáférést biztosít a(z) <xliff:g id="APPNAME"><b>^1</b></xliff:g> alkalmazásnak a(z) <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> könyvtárhoz?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Hozzáférést biztosít a(z) <xliff:g id="APPNAME"><b>^1</b></xliff:g> számára az Ön adataihoz, beleértve a következő tárhelyen található képekhez és videókhoz: <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Ne jelenjen meg többé"</string>
<string name="allow" msgid="7225948811296386551">"Engedélyezés"</string>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
index b1af92c..f6c3ad5 100644
--- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml
+++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Չհաջողվեց վերանվանել փաստաթուղթը"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Որոշ ֆայլեր փոխարկվել են"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> հավելվածին տրամադրե՞լ <xliff:g id="STORAGE"><i>^3</i></xliff:g>-ի <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> գրացուցակն օգտագործելու թույլտվություն:"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> հավելվածին տրամադրե՞լ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> գրացուցակն օգտագործելու թույլտվություն:"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> հավելվածին տրամադրե՞լ <xliff:g id="STORAGE"><i>^2</i></xliff:g>-ում պահվող ձեր տվյալները, այդ թվում նաև լուսանկարները և տեսանյութերը, օգտագործելու թույլտվություն:"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Այլևս չհարցնել"</string>
<string name="allow" msgid="7225948811296386551">"Թույլատրել"</string>
diff --git a/packages/DocumentsUI/res/values-in/strings.xml b/packages/DocumentsUI/res/values-in/strings.xml
index 87576fb..a8aee52 100644
--- a/packages/DocumentsUI/res/values-in/strings.xml
+++ b/packages/DocumentsUI/res/values-in/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Gagal mengganti nama dokumen"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Beberapa file dikonversi"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Beri <xliff:g id="APPNAME"><b>^1</b></xliff:g> akses ke direktori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> di <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Beri <xliff:g id="APPNAME"><b>^1</b></xliff:g> akses ke direktori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Beri <xliff:g id="APPNAME"><b>^1</b></xliff:g> akses ke data Anda, termasuk foto dan video, di <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Jangan tanya lagi"</string>
<string name="allow" msgid="7225948811296386551">"Izinkan"</string>
diff --git a/packages/DocumentsUI/res/values-is-rIS/strings.xml b/packages/DocumentsUI/res/values-is-rIS/strings.xml
index d3be73a..88aaced 100644
--- a/packages/DocumentsUI/res/values-is-rIS/strings.xml
+++ b/packages/DocumentsUI/res/values-is-rIS/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Ekki tókst að endurnefna skjalið"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sumum skrám var umbreytt"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Veita <xliff:g id="APPNAME"><b>^1</b></xliff:g> aðgang að skráasafninu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> á <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Viltu veita <xliff:g id="APPNAME"><b>^1</b></xliff:g> aðgang að skráasafninu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Veita <xliff:g id="APPNAME"><b>^1</b></xliff:g> aðgang að gögnunum þínum, þar á meðal myndum og myndskeiðum, á <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Ekki spyrja aftur"</string>
<string name="allow" msgid="7225948811296386551">"Leyfa"</string>
diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml
index 736d31c..b7497db 100644
--- a/packages/DocumentsUI/res/values-it/strings.xml
+++ b/packages/DocumentsUI/res/values-it/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Ridenominazione documento non riuscita"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alcuni file sono stati convertiti"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Concedere all\'app <xliff:g id="APPNAME"><b>^1</b></xliff:g> l\'accesso alla directory <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> su <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Concedere all\'app <xliff:g id="APPNAME"><b>^1</b></xliff:g> l\'accesso alla directory <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Concedere all\'app <xliff:g id="APPNAME"><b>^1</b></xliff:g> l\'accesso ai tuoi dati, inclusi video e foto, sull\'unità <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Non chiedermelo più"</string>
<string name="allow" msgid="7225948811296386551">"Consenti"</string>
diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml
index 2446a4b..4498f8c 100644
--- a/packages/DocumentsUI/res/values-iw/strings.xml
+++ b/packages/DocumentsUI/res/values-iw/strings.xml
@@ -125,6 +125,7 @@
<string name="rename_error" msgid="4203041674883412606">"ניסיון שינוי שם המסמך נכשל"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"קבצים מסוימים הומרו"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"האם להעניק לאפליקציה <xliff:g id="APPNAME"><b>^1</b></xliff:g> גישה לספריה <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> באחסון <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"האם להעניק לאפליקציה <xliff:g id="APPNAME"><b>^1</b></xliff:g> גישה אל ספריית <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"האם להעניק לאפליקציה <xliff:g id="APPNAME"><b>^1</b></xliff:g> גישה לנתונים שלך, כולל תמונות וסרטונים, השמורים ב<xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"אל תשאל שוב"</string>
<string name="allow" msgid="7225948811296386551">"אפשר"</string>
diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml
index dc39b99..bfb1c3a 100644
--- a/packages/DocumentsUI/res/values-ja/strings.xml
+++ b/packages/DocumentsUI/res/values-ja/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"ドキュメントの名前を変更できませんでした"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"一部のファイルが変換されました"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"「<xliff:g id="STORAGE"><i>^3</i></xliff:g>」の「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」ディレクトリに「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」へのアクセスを許可しますか?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」アプリに「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」ディレクトリへのアクセスを許可しますか?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g>の写真や動画などのデータへのアクセスを「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」に許可しますか?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"今後表示しない"</string>
<string name="allow" msgid="7225948811296386551">"許可"</string>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
index 0af8dd9..f0e9e86 100644
--- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml
+++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"დოკუმენტის გადარქმევა ვერ მოხერხდა"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ზოგიერთი ფაილი გარდაქმნილია"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"გსურთ, <xliff:g id="APPNAME"><b>^1</b></xliff:g> სარგებლობდეს <xliff:g id="STORAGE"><i>^3</i></xliff:g>-ის დირექტორიაზე „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“ წვდომის უფლებით?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"გსურთ, <xliff:g id="APPNAME"><b>^1</b></xliff:g> სარგებლობდეს დირექტორიაზე „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“ წვდომის უფლებით?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"გსურთ, <xliff:g id="APPNAME"><b>^1</b></xliff:g> სარგებლობდეს <xliff:g id="STORAGE"><i>^2</i></xliff:g>-ზე არსებულ მონაცემებზე, მათ შორის, ფოტოებსა და ვიდეოებზე, წვდომის უფლებით?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"აღარ მკითხოთ"</string>
<string name="allow" msgid="7225948811296386551">"უფლების მიცემა"</string>
diff --git a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
index 3d6b758..2687900 100644
--- a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
+++ b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Құжат қайта аталмады"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Кейбір файлдар түрлендірілді"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> қолданбасына <xliff:g id="STORAGE"><i>^3</i></xliff:g> қоймасындағы <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> каталогына өтуге рұқсат беру керек пе?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> қолданбасына <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> каталогына қатынас беру керек пе?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> <xliff:g id="STORAGE"><i>^2</i></xliff:g> қоймасындағы деректерге, соның ішінде фотосуреттерге және бейнелерге кіру мүмкіндігін беру керек пе?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Қайта сұралмасын"</string>
<string name="allow" msgid="7225948811296386551">"Рұқсат беру"</string>
diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml
index 0eb1396..ea24043 100644
--- a/packages/DocumentsUI/res/values-km-rKH/strings.xml
+++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"បានបរាជ័យក្នុងការប្តូរឈ្មោះឯកសារ"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ឯកសារមួយចំនួនត្រូវបានបម្លែង"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"ផ្តល់សិទ្ធិឲ្យ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ចូលដំណើរការថត <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> នៅលើ <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"ផ្តល់សិទ្ធិឲ្យ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ចូលដំណើរការថត <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ឬ?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"ផ្តល់សិទ្ធិអនុញ្ញាតដល់ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ដើម្បីចូលដំណើរការទិន្នន័យរបស់អ្នក រាប់បញ្ចូលទាំងរូបថត និងវីដេអូ នៅលើ <xliff:g id="STORAGE"><i>^2</i></xliff:g> ឬទេ?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"កុំសួរទៀត"</string>
<string name="allow" msgid="7225948811296386551">"អនុញ្ញាត"</string>
diff --git a/packages/DocumentsUI/res/values-kn-rIN/strings.xml b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
index a5a8ab2..c756009 100644
--- a/packages/DocumentsUI/res/values-kn-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"ಡಾಕ್ಯುಮೆಂಟ್ ಮರುಹೆಸರಿಸಲು ವಿಫಲವಾಗಿದೆ"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ಕೆಲವು ಫೈಲ್ಗಳನ್ನು ಪರಿವರ್ತಿಸಲಾಗಿದೆ"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g> ರಲ್ಲಿ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ಡೈರೆಕ್ಟರಿಗೆ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ಪ್ರವೇಶ ನೀಡುವುದೇ?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g><xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ಡೈರೆಕ್ಟರಿ ಪ್ರವೇಶಿಸಲು ಅನುಮತಿಸುವುದೇ?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g> ಸಂಗ್ರಹಣೆಯಲ್ಲಿನ ಪೋಟೋಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳು ಸೇರಿದಂತೆ ನಿಮ್ಮ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಲು <xliff:g id="APPNAME"><b>^1</b></xliff:g> ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುವುದೇ?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"ಮತ್ತೆ ಕೇಳಬೇಡಿ"</string>
<string name="allow" msgid="7225948811296386551">"ಅನುಮತಿಸು"</string>
diff --git a/packages/DocumentsUI/res/values-ko/strings.xml b/packages/DocumentsUI/res/values-ko/strings.xml
index 9975ce0..4d5dcf9 100644
--- a/packages/DocumentsUI/res/values-ko/strings.xml
+++ b/packages/DocumentsUI/res/values-ko/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"문서 이름을 변경하지 못했습니다."</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"일부 파일이 변환되었습니다."</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g>이(가) <xliff:g id="STORAGE"><i>^3</i></xliff:g>에서 <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> 디렉토리에 액세스하도록 허용하시겠습니까?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g>이(가) <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> 디렉토리에 액세스하도록 허용하시겠습니까?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g>에서 사진, 동영상 등 <xliff:g id="STORAGE"><i>^2</i></xliff:g>의 내 데이터에 액세스하도록 허용하시겠습니까?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"다시 묻지 않음"</string>
<string name="allow" msgid="7225948811296386551">"허용"</string>
diff --git a/packages/DocumentsUI/res/values-ky-rKG/strings.xml b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
index be2aca8..1b39039 100644
--- a/packages/DocumentsUI/res/values-ky-rKG/strings.xml
+++ b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Документтин аталышы өзгөртүлбөй калды"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Айрым файлдардын форматы өзгөртүлдү"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> колдонмосуна <xliff:g id="STORAGE"><i>^3</i></xliff:g> түзмөгүндөгү <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> папканы пайдалануу мүмкүнчүлүгү берилсинби?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> колдонмосуна <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> каталогун пайдалануу мүмкүнчүлүгү берилсинби?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> колдонмосуна <xliff:g id="STORAGE"><i>^2</i></xliff:g> түзмөгүндөгү дайындарыңыз, сүрөттөрүңүз жана видеолоруңузду пайдалануу мүмкүнчүлүгү берилсинби?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Экинчи суралбасын"</string>
<string name="allow" msgid="7225948811296386551">"Уруксат берүү"</string>
@@ -130,7 +131,7 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> куржун мазмуну менен жок кылынсынбы?</item>
</plurals>
<plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
- <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> нерсе жок кылынчынбы?</item>
- <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> нерсе жок кылынчынбы?</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> нерсе жок кылынсынбы?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> нерсе жок кылынсынбы?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
index ed96464..a4f381d 100644
--- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml
+++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"ປ່ຽນຊື່ເອກະສານບໍ່ສຳເລັດ"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ປ່ຽນແປງບາງໄຟລ໌ແລ້ວ"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"ອະນຸຍາດສິດເຂົ້າເຖິງໃຫ້ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ເພື່ອເຂົ້າໄດເຣກທໍຣີ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ຢູ່ <xliff:g id="STORAGE"><i>^3</i></xliff:g> ບໍ?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"ອະນຸມັດ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ໃຫ້ເຂົ້າຫາໄດເຣັກທໍຣີ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ບໍ?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"ອະນຸມັດໃຫ້ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ເຂົ້າເຖິງຂໍ້ມູນຂອງທ່ານ ເຊິ່ງຮວມເຖິງຮູບພາບ ແລະ ວິດີໂອໃນ <xliff:g id="STORAGE"><i>^2</i></xliff:g> ໄດ້ບໍ?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"ບໍ່ຕ້ອງຖາມຄືນ"</string>
<string name="allow" msgid="7225948811296386551">"ອະນຸຍາດ"</string>
diff --git a/packages/DocumentsUI/res/values-lt/strings.xml b/packages/DocumentsUI/res/values-lt/strings.xml
index 0e95ea0..2e0df93 100644
--- a/packages/DocumentsUI/res/values-lt/strings.xml
+++ b/packages/DocumentsUI/res/values-lt/strings.xml
@@ -125,6 +125,7 @@
<string name="rename_error" msgid="4203041674883412606">"Nepavyko pervardyti dokumento"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Kai kurie failai buvo konvertuoti"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Suteikti „<xliff:g id="APPNAME"><b>^1</b></xliff:g>“ prieigą prie katalogo „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“ <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Suteikti „<xliff:g id="APPNAME"><b>^1</b></xliff:g>“ prieigą prie katalogo „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Suteikti programai „<xliff:g id="APPNAME"><b>^1</b></xliff:g>“ prieigą prie duomenų, įskaitant nuotraukas ir vaizdo įrašus, <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Daugiau neklausti"</string>
<string name="allow" msgid="7225948811296386551">"Leisti"</string>
diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml
index 9f39f2e..fb81aa0 100644
--- a/packages/DocumentsUI/res/values-lv/strings.xml
+++ b/packages/DocumentsUI/res/values-lv/strings.xml
@@ -118,6 +118,7 @@
<string name="rename_error" msgid="4203041674883412606">"Neizdevās pārdēvēt dokumentu"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Daži faili tika pārveidoti."</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Vai atļaut lietotnei <xliff:g id="APPNAME"><b>^1</b></xliff:g> piekļūt direktorijam <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> šajā krātuvē: <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Vai piešķirt lietotnei <xliff:g id="APPNAME"><b>^1</b></xliff:g> piekļuvi direktorijam <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Vai atļaut lietotnei <xliff:g id="APPNAME"><b>^1</b></xliff:g> piekļūt jūsu datiem, tostarp fotoattēliem un videoklipiem, šajā krātuvē: <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Turpmāk vairs nejautāt"</string>
<string name="allow" msgid="7225948811296386551">"Atļaut"</string>
diff --git a/packages/DocumentsUI/res/values-mk-rMK/strings.xml b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
index bc3b7fa..ad428a0 100644
--- a/packages/DocumentsUI/res/values-mk-rMK/strings.xml
+++ b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Не успеа да се преименува документот"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Некои датотеки беа конвертирани"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Овозможете пристап на <xliff:g id="APPNAME"><b>^1</b></xliff:g> до директориумот <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> на <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Овозможете пристап на <xliff:g id="APPNAME"><b>^1</b></xliff:g> до директориумот <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Да се овозможи пристап на <xliff:g id="APPNAME"><b>^1</b></xliff:g> до вашите податоци, вклучувајќи фотографии и видеа, на <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Не прашувај повторно"</string>
<string name="allow" msgid="7225948811296386551">"Дозволи"</string>
diff --git a/packages/DocumentsUI/res/values-ml-rIN/strings.xml b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
index 9a7509f..5a16512 100644
--- a/packages/DocumentsUI/res/values-ml-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"ഡോക്യുമെന്റിന്റെ പേരുമാറ്റുന്നത് പരാജയപ്പെട്ടു"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ചില ഫയലുകൾ പരിവർത്തനം ചെയ്യപ്പെട്ടു"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g> സ്റ്റോറേജിലെ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> എന്ന ഡയറക്റ്ററിയിലേക്ക് <xliff:g id="APPNAME"><b>^1</b></xliff:g> ആപ്പിന് ആക്സസ് അനുവദിക്കണോ?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> എന്ന ഡയറക്ടറിയിലേക്ക് <xliff:g id="APPNAME"><b>^1</b></xliff:g> ആപ്പിന് ആക്സസ് അനുവദിക്കണോ?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g> സ്റ്റോറേജിലെ ഫോട്ടോകളും വീഡിയോകളും ഉൾപ്പെടെ, നിങ്ങളുടെ ഡാറ്റയിലേക്ക് <xliff:g id="APPNAME"><b>^1</b></xliff:g> ആപ്പിന് ആക്സസ്സ് അനുവദിക്കണോ?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"വീണ്ടും ആവശ്യപ്പെടരുത്"</string>
<string name="allow" msgid="7225948811296386551">"അനുവദിക്കുക"</string>
diff --git a/packages/DocumentsUI/res/values-mn-rMN/strings.xml b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
index f424f8e..cf2c2d4 100644
--- a/packages/DocumentsUI/res/values-mn-rMN/strings.xml
+++ b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Баримт бичгийн нэрийн өөрчилж чадсангүй"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Зарим файлыг хөрвүүлсэн"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g>-д байгаа <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> лавлагаанд хандахыг <xliff:g id="APPNAME"><b>^1</b></xliff:g>-д зөвшөөрөх үү?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> лавлагаанд хандах эрхийг <xliff:g id="APPNAME"><b>^1</b></xliff:g>-д олгох уу?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g>-д байгаа зураг, видео гэх мэт таны өгөгдөлд <xliff:g id="APPNAME"><b>^1</b></xliff:g> хандахыг зөвшөөрөх үү?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Дахин бүү асуу"</string>
<string name="allow" msgid="7225948811296386551">"Зөвшөөрөх"</string>
diff --git a/packages/DocumentsUI/res/values-mr-rIN/strings.xml b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
index 556c1e6..09dd133 100644
--- a/packages/DocumentsUI/res/values-mr-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"दस्तऐवज पुनर्नामित करण्यात अयशस्वी झाले"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"काही फायली रूपांतरित केल्या होत्या"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g> वर <xliff:g id="APPNAME"><b>^1</b></xliff:g> ला <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिकेवर प्रवेशाची मंजूरी द्यायची?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ला <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिकमध्ये प्रवेश मंजूर करायचा?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ला <xliff:g id="STORAGE"><i>^2</i></xliff:g> वर फोटो आणि व्हिडिओंसह, आपल्या डेटामध्ये प्रवेश करण्याची मंजूरी द्यायची?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"पुन्हा विचारू नका"</string>
<string name="allow" msgid="7225948811296386551">"अनुमती द्या"</string>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
index 0f2af2f..9eb3d49 100644
--- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml
+++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Gagal menamakan semula dokumen"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sesetengah fail telah ditukarkan"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Beri <xliff:g id="APPNAME"><b>^1</b></xliff:g> akses kepada direktori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> di <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Beri <xliff:g id="APPNAME"><b>^1</b></xliff:g> akses kepada direktori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Beri <xliff:g id="APPNAME"><b>^1</b></xliff:g> akses kepada data anda, termasuk foto dan video pada <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Jangan tanya lagi"</string>
<string name="allow" msgid="7225948811296386551">"Benarkan"</string>
diff --git a/packages/DocumentsUI/res/values-my-rMM/strings.xml b/packages/DocumentsUI/res/values-my-rMM/strings.xml
index 6acbc80..7c637c4 100644
--- a/packages/DocumentsUI/res/values-my-rMM/strings.xml
+++ b/packages/DocumentsUI/res/values-my-rMM/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"စာရွက်စာတမ်းကို အမည်ပြောင်းခြင်း မအောင်မြင်ပါ"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"အချို့ဖိုင်များကို ပြောင်းလဲထားသည်"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ကို <xliff:g id="STORAGE"><i>^3</i></xliff:g> ရှိ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> လမ်းညွှန်အား အသုံးပြုခွင့်ပေးမလား။"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> အား <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> စာရင်းကို အသုံးပြုခွင့်ပေးမလား။"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g> ရှိဓာတ်ပုံများနှင့် ဗီဒီယိုများအပါအဝင် သင့်ဒေတာများကို <xliff:g id="APPNAME"><b>^1</b></xliff:g> အားအသုံးပြုခွင့်ပေးမလား။"</string>
<string name="never_ask_again" msgid="4295278542972859268">"နောက်ထပ်မမေးပါနှင့်"</string>
<string name="allow" msgid="7225948811296386551">"ခွင့်ပြုသည်"</string>
diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml
index c2c983e..3c344eb 100644
--- a/packages/DocumentsUI/res/values-nb/strings.xml
+++ b/packages/DocumentsUI/res/values-nb/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Kunne ikke gi dokumentet nytt navn"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Noen filer er konvertert"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Vil du gi <xliff:g id="APPNAME"><b>^1</b></xliff:g> tilgang til <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>-katalogen på <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Vil du gi <xliff:g id="APPNAME"><b>^1</b></xliff:g> tilgang til <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>-katalogen?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Vil du gi <xliff:g id="APPNAME"><b>^1</b></xliff:g> tilgang til dataene dine – inkludert bilder og videoer – på <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Ikke spør igjen"</string>
<string name="allow" msgid="7225948811296386551">"Tillat"</string>
diff --git a/packages/DocumentsUI/res/values-ne-rNP/strings.xml b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
index 31c4c2c..9fef037 100644
--- a/packages/DocumentsUI/res/values-ne-rNP/strings.xml
+++ b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"कागजात पुन: नामाकरण गर्न असफल भयो"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"केही फाइलहरू परिवर्तन गरिएका थिए"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> लाई <xliff:g id="STORAGE"><i>^3</i></xliff:g> मा भएको <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिकामा पहुँच गर्न अनुमति दिने हो?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> लाई <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिकामाथि पहुँच गर्न अनुमति प्रदान गर्ने हो?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> लाई <xliff:g id="STORAGE"><i>^2</i></xliff:g> मा भएका तस्बिर र भिडियोहरू लगायत तपाईँको डेटामा पहुँच गर्नका लागि अनुमति दिने हो?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"फेरि नसोध्नुहोस्"</string>
<string name="allow" msgid="7225948811296386551">"अनुमति दिनुहोस्"</string>
diff --git a/packages/DocumentsUI/res/values-nl/strings.xml b/packages/DocumentsUI/res/values-nl/strings.xml
index 385b507..c5b9d76 100644
--- a/packages/DocumentsUI/res/values-nl/strings.xml
+++ b/packages/DocumentsUI/res/values-nl/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Kan naam van document niet wijzigen"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sommige bestanden zijn geconverteerd"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> toegang verlenen tot de map <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> op <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> toegang verlenen tot de map <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> toegang verlenen tot je gegevens, waaronder foto\'s en video\'s, op <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Niet meer vragen"</string>
<string name="allow" msgid="7225948811296386551">"Toestaan"</string>
diff --git a/packages/DocumentsUI/res/values-pa-rIN/strings.xml b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
index 7603f58..7d5e14a 100644
--- a/packages/DocumentsUI/res/values-pa-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"ਦਸਤਾਵੇਜ਼ ਦਾ ਮੁੜ-ਨਾਮਕਰਨ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ਕੁਝ ਫ਼ਾਈਲਾਂ ਤਬਦੀਲ ਕੀਤੀਆਂ ਗਈਆਂ ਸਨ"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"ਕੀ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ਨੂੰ <xliff:g id="STORAGE"><i>^3</i></xliff:g> \'ਤੇ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ਡਾਇਰੈਕਟਰੀ \'ਤੇ ਪਹੁੰਚ ਦੇਣੀ ਹੈ?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"ਕੀ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ਨੂੰ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ਡਾਇਰੈਕਟਰੀ \'ਤੇ ਪਹੁੰਚ ਦੇਣੀ ਹੈ?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"ਕੀ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ਨੂੰ <xliff:g id="STORAGE"><i>^2</i></xliff:g> \'ਤੇ ਫੋਟੋਆਂ ਅਤੇ ਵੀਡੀਓ ਸਮੇਤ, ਤੁਹਾਡੇ ਡੈਟੇ \'ਤੇ ਪਹੁੰਚ ਦੇਣੀ ਹੈ?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"ਦੁਬਾਰਾ ਨਾ ਪੁੱਛੋ"</string>
<string name="allow" msgid="7225948811296386551">"ਆਗਿਆ ਦਿਓ"</string>
diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml
index b234a9e..ca007d7 100644
--- a/packages/DocumentsUI/res/values-pl/strings.xml
+++ b/packages/DocumentsUI/res/values-pl/strings.xml
@@ -125,6 +125,7 @@
<string name="rename_error" msgid="4203041674883412606">"Nie udało się zmienić nazwy dokumentu"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Niektóre pliki zostały przekonwertowane"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Zezwolić aplikacji <xliff:g id="APPNAME"><b>^1</b></xliff:g> na dostęp do katalogu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> w pamięci masowej <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Przyznać aplikacji <xliff:g id="APPNAME"><b>^1</b></xliff:g> dostęp do katalogu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Zezwolić aplikacji <xliff:g id="APPNAME"><b>^1</b></xliff:g> na dostęp do Twoich danych, w tym zdjęć i filmów, zapisanych w pamięci <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Nie pytaj ponownie"</string>
<string name="allow" msgid="7225948811296386551">"Zezwól"</string>
diff --git a/packages/DocumentsUI/res/values-pt-rBR/strings.xml b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
index 634ac96..21359c7 100644
--- a/packages/DocumentsUI/res/values-pt-rBR/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Falha ao renomear documento"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alguns arquivos foram convertidos"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Conceder ao <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> no <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Conceder acesso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Conceder a <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso aos seus dados, incluindo fotos e vídeos, no/na <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Não perguntar novamente"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
index 5440801..aea1249 100644
--- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Falha ao mudar o nome do documento"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alguns ficheiros foram convertidos"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Pretende conceder a <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> no(a) <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Pretende conceder a <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Pretende conceder a <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso aos seus dados, incluindo fotos e vídeos, no(a) <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Não perguntar novamente"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml
index 634ac96..21359c7 100644
--- a/packages/DocumentsUI/res/values-pt/strings.xml
+++ b/packages/DocumentsUI/res/values-pt/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Falha ao renomear documento"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alguns arquivos foram convertidos"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Conceder ao <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> no <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Conceder acesso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Conceder a <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso aos seus dados, incluindo fotos e vídeos, no/na <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Não perguntar novamente"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml
index 3dc93ef..4b833b1 100644
--- a/packages/DocumentsUI/res/values-ro/strings.xml
+++ b/packages/DocumentsUI/res/values-ro/strings.xml
@@ -118,6 +118,7 @@
<string name="rename_error" msgid="4203041674883412606">"Documentul nu a putut fi redenumit"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Unele fișiere au fost convertite"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Permiteți aplicației <xliff:g id="APPNAME"><b>^1</b></xliff:g> accesul la directorul <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> de pe <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Permiteți aplicației <xliff:g id="APPNAME"><b>^1</b></xliff:g> să acceseze directorul <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Permiteți aplicației <xliff:g id="APPNAME"><b>^1</b></xliff:g> să vă acceseze datele, inclusiv fotografiile și videoclipurile, de pe <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Nu mai întreba"</string>
<string name="allow" msgid="7225948811296386551">"Permiteți"</string>
diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml
index fef3015..6ba635d 100644
--- a/packages/DocumentsUI/res/values-ru/strings.xml
+++ b/packages/DocumentsUI/res/values-ru/strings.xml
@@ -125,6 +125,7 @@
<string name="rename_error" msgid="4203041674883412606">"Не удалось переименовать документ"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Формат некоторых файлов изменен"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Открыть приложению \"<xliff:g id="APPNAME"><b>^1</b></xliff:g>\" доступ к папке \"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>\" на устройстве \"<xliff:g id="STORAGE"><i>^3</i></xliff:g>\"?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Открыть приложению \"<xliff:g id="APPNAME"><b>^1</b></xliff:g>\" доступ к папке \"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>\"?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Открыть приложению \"<xliff:g id="APPNAME"><b>^1</b></xliff:g>\" доступ к вашим данным, включая фото и видео, на носителе: <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Больше не спрашивать"</string>
<string name="allow" msgid="7225948811296386551">"Разрешить"</string>
diff --git a/packages/DocumentsUI/res/values-si-rLK/strings.xml b/packages/DocumentsUI/res/values-si-rLK/strings.xml
index d49c2f3..41c9d4a 100644
--- a/packages/DocumentsUI/res/values-si-rLK/strings.xml
+++ b/packages/DocumentsUI/res/values-si-rLK/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"ලේඛනය යළි නම් කිරීම අසාර්ථක විය"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"සමහර ගොනු පරිවර්තනය කරන ලදී"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> හට <xliff:g id="STORAGE"><i>^3</i></xliff:g> මත <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> නාමාවලිය වෙත ප්රවේශය දෙන්නද?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ප්රවේශය <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> නාමාවලිය වෙත ලබා දෙන්නද?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g> හි, ඡායාරූප සහ වීඩියෝ ඇතුළුව, ඔබේ දත්තවලට <xliff:g id="APPNAME"><b>^1</b></xliff:g> හට ප්රවේශය ලබා දෙන්නද?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"නැවත අසන්න එපා"</string>
<string name="allow" msgid="7225948811296386551">"අවසර දෙන්න"</string>
diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml
index bd75175..1ff01b0 100644
--- a/packages/DocumentsUI/res/values-sk/strings.xml
+++ b/packages/DocumentsUI/res/values-sk/strings.xml
@@ -125,6 +125,7 @@
<string name="rename_error" msgid="4203041674883412606">"Premenovanie dokumentu zlyhalo"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Niektoré súbory boli konvertované"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Udeliť aplikácii <xliff:g id="APPNAME"><b>^1</b></xliff:g> prístup k adresáru <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> v úložisku <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Udeliť aplikácii <xliff:g id="APPNAME"><b>^1</b></xliff:g> prístup k adresáru <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Chcete aplikácii <xliff:g id="APPNAME"><b>^1</b></xliff:g> udeliť prístup k dátam (vrátane fotiek a videí) v úložisku <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Nabudúce sa nepýtať"</string>
<string name="allow" msgid="7225948811296386551">"Povoliť"</string>
diff --git a/packages/DocumentsUI/res/values-sl/strings.xml b/packages/DocumentsUI/res/values-sl/strings.xml
index 78ec8fe..d8b983c 100644
--- a/packages/DocumentsUI/res/values-sl/strings.xml
+++ b/packages/DocumentsUI/res/values-sl/strings.xml
@@ -125,6 +125,7 @@
<string name="rename_error" msgid="4203041674883412606">"Dokumenta ni bilo mogoče preimenovati"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Nekatere datoteke so bile pretvorjene"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Želite aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> dovoliti dostop do imenika <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> v shrambi <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Želite aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> dovoliti dostop do imenika <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Odobrite aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> dostop do podatkov, vključno s fotografijami in videoposnetki, v shrambi <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Ne sprašuj več"</string>
<string name="allow" msgid="7225948811296386551">"Dovoli"</string>
diff --git a/packages/DocumentsUI/res/values-sq-rAL/strings.xml b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
index 662e7f0..933a537 100644
--- a/packages/DocumentsUI/res/values-sq-rAL/strings.xml
+++ b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Riemërtimi i dokumentit dështoi"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Disa skedarë u konvertuan"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Jepi aplikacionit <xliff:g id="APPNAME"><b>^1</b></xliff:g> qasje te direktoria <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> në <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"T\'i jepet aplikacionit <xliff:g id="APPNAME"><b>^1</b></xliff:g> qasje te direktoria <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"T\'i jepet aplikacionit <xliff:g id="APPNAME"><b>^1</b></xliff:g> qasje te të dhënat, duke përfshirë fotografitë dhe videot, në <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Mos pyet përsëri"</string>
<string name="allow" msgid="7225948811296386551">"Lejo"</string>
diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml
index 690f81c..0505f42 100644
--- a/packages/DocumentsUI/res/values-sr/strings.xml
+++ b/packages/DocumentsUI/res/values-sr/strings.xml
@@ -118,6 +118,7 @@
<string name="rename_error" msgid="4203041674883412606">"Преименовање документа није успело"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Неке датотеке су конвертоване"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Желите ли да апликацији <xliff:g id="APPNAME"><b>^1</b></xliff:g> одобрите приступ директоријуму <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> на меморијском простору <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Желите да дозволите да <xliff:g id="APPNAME"><b>^1</b></xliff:g> приступа директоријуму <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Желите да ли да дозволите да апликација <xliff:g id="APPNAME"><b>^1</b></xliff:g> приступа подацима, укључујући слике и видео снимке, на локацији <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Не питај поново"</string>
<string name="allow" msgid="7225948811296386551">"Дозволи"</string>
diff --git a/packages/DocumentsUI/res/values-sv/strings.xml b/packages/DocumentsUI/res/values-sv/strings.xml
index 1849782..99f334b 100644
--- a/packages/DocumentsUI/res/values-sv/strings.xml
+++ b/packages/DocumentsUI/res/values-sv/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Det gick inte att byta namn på dokumentet"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Vissa filer konverterades"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Vill du ge <xliff:g id="APPNAME"><b>^1</b></xliff:g> åtkomst till katalogen <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> på <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Vill du ge <xliff:g id="APPNAME"><b>^1</b></xliff:g> åtkomst till katalogen <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Vill du ge <xliff:g id="APPNAME"><b>^1</b></xliff:g> åtkomst till din data (inklusive foton och videor) på <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Fråga inte igen"</string>
<string name="allow" msgid="7225948811296386551">"Tillåt"</string>
diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml
index bf4b744..566e6a4 100644
--- a/packages/DocumentsUI/res/values-sw/strings.xml
+++ b/packages/DocumentsUI/res/values-sw/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Imeshindwa kubadilisha jina la hati"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Baadhi ya faili zimebadilishwa muundo"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Ungependa kuruhusu <xliff:g id="APPNAME"><b>^1</b></xliff:g> ifikie saraka ya <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> kwenye <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Ungependa kuruhusu <xliff:g id="APPNAME"><b>^1</b></xliff:g> ifikie saraka ya <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Ungependa kuruhusu <xliff:g id="APPNAME"><b>^1</b></xliff:g> ifikie data yako, ikiwa ni pamoja na picha na video kwenye <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Usiniulize tena"</string>
<string name="allow" msgid="7225948811296386551">"Ruhusu"</string>
diff --git a/packages/DocumentsUI/res/values-ta-rIN/strings.xml b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
index 43d29e2..9a8b4ec 100644
--- a/packages/DocumentsUI/res/values-ta-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"ஆவணத்திற்கு மறுபெயரிடுவதில் தோல்வி"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"சில கோப்புகள் மாற்றப்பட்டன"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g> இல் உள்ள <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> கோப்பகத்தை அணுக <xliff:g id="APPNAME"><b>^1</b></xliff:g>ஐ அனுமதிக்கவா?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> கோப்பகத்தை அணுக, <xliff:g id="APPNAME"><b>^1</b></xliff:g>ஐ அனுமதிக்கவா?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g> இல் உள்ள படங்கள், வீடியோக்கள் உட்பட எல்லா தரவையும் அணுக, <xliff:g id="APPNAME"><b>^1</b></xliff:g>ஐ அனுமதிக்கவா?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"மீண்டும் கேட்காதே"</string>
<string name="allow" msgid="7225948811296386551">"அனுமதி"</string>
diff --git a/packages/DocumentsUI/res/values-te-rIN/strings.xml b/packages/DocumentsUI/res/values-te-rIN/strings.xml
index c9233ec..224d0db 100644
--- a/packages/DocumentsUI/res/values-te-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-te-rIN/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"పత్రం పేరు మార్చడంలో విఫలమైంది"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"కొన్ని పైల్లు మార్చబడ్డాయి"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g>కి <xliff:g id="STORAGE"><i>^3</i></xliff:g>లో <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> డైరెక్టరీ ప్రాప్యతను మంజూరు చేయాలా?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g>కి <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> డైరెక్టరీ ప్రాప్యతను మంజూరు చేయాలా?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g>లో ఫోటోలు మరియు వీడియోలతో సహా మీ డేటా ప్రాప్యతను <xliff:g id="APPNAME"><b>^1</b></xliff:g>కి మంజూరు చేయాలా?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"మళ్లీ అడగవద్దు"</string>
<string name="allow" msgid="7225948811296386551">"అనుమతించండి"</string>
diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml
index 491e984..af07584 100644
--- a/packages/DocumentsUI/res/values-th/strings.xml
+++ b/packages/DocumentsUI/res/values-th/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"ไม่สามารถเปลี่ยนชื่อเอกสาร"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"แปลงบางไฟล์แล้ว"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"ให้สิทธิ์ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ในการเข้าถึงไดเรกทอรี <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ใน <xliff:g id="STORAGE"><i>^3</i></xliff:g> ไหม"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"ให้สิทธิ์ <xliff:g id="APPNAME"><b>^1</b></xliff:g> เข้าถึงไดเรกทอรี <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ไหม"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"ให้สิทธิ์ <xliff:g id="APPNAME"><b>^1</b></xliff:g> เข้าถึงข้อมูลของคุณ รวมถึงรูปภาพและวิดีโอใน <xliff:g id="STORAGE"><i>^2</i></xliff:g> ไหม"</string>
<string name="never_ask_again" msgid="4295278542972859268">"ไม่ต้องถามอีก"</string>
<string name="allow" msgid="7225948811296386551">"อนุญาต"</string>
diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml
index 27d6671..b2acf05 100644
--- a/packages/DocumentsUI/res/values-tl/strings.xml
+++ b/packages/DocumentsUI/res/values-tl/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Hindi napalitan ang pangalan ng dokumento"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Na-convert ang ilang file"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Bigyan ang <xliff:g id="APPNAME"><b>^1</b></xliff:g> ng access sa directory ng <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> sa <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Bibigyan ang <xliff:g id="APPNAME"><b>^1</b></xliff:g> ng access sa direktoryong <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Bigyan ang <xliff:g id="APPNAME"><b>^1</b></xliff:g> ng access sa iyong data, kabilang ang mga larawan at video, sa <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Huwag nang tatanunging muli"</string>
<string name="allow" msgid="7225948811296386551">"Payagan"</string>
diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml
index dda9f28..c5653c9 100644
--- a/packages/DocumentsUI/res/values-tr/strings.xml
+++ b/packages/DocumentsUI/res/values-tr/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Dokümanın adı değiştirilemedi"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Bazı dosyalar dönüştürüldü"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> uygulamasına <xliff:g id="STORAGE"><i>^3</i></xliff:g> depolama alanındaki <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> dizinine erişim izni verilsin mi?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> dizinine erişmek için <xliff:g id="APPNAME"><b>^1</b></xliff:g> uygulamasına izin verilsin mi?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> uygulamasının, fotoğraflar ve videolar dahil olmak üzere <xliff:g id="STORAGE"><i>^2</i></xliff:g> üzerindeki verilerinize erişmesine izin verilsin mi?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Tekrar sorma"</string>
<string name="allow" msgid="7225948811296386551">"İzin Ver"</string>
diff --git a/packages/DocumentsUI/res/values-uk/strings.xml b/packages/DocumentsUI/res/values-uk/strings.xml
index ec7e1d6..21532b6 100644
--- a/packages/DocumentsUI/res/values-uk/strings.xml
+++ b/packages/DocumentsUI/res/values-uk/strings.xml
@@ -125,6 +125,7 @@
<string name="rename_error" msgid="4203041674883412606">"Не вдалося перейменувати документ"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Деякі файли конвертовано"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Надати додатку <xliff:g id="APPNAME"><b>^1</b></xliff:g> доступ до каталогу <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> на пристрої пам’яті <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Надати додатку <xliff:g id="APPNAME"><b>^1</b></xliff:g> доступ до каталогу \"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>\"?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Надати додатку <xliff:g id="APPNAME"><b>^1</b></xliff:g> доступ до ваших даних, зокрема до фотографій і відео, які містить <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Не запитувати знову"</string>
<string name="allow" msgid="7225948811296386551">"Дозвол."</string>
diff --git a/packages/DocumentsUI/res/values-ur-rPK/strings.xml b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
index 4ea9985..eb0cfc8 100644
--- a/packages/DocumentsUI/res/values-ur-rPK/strings.xml
+++ b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"دستاویز کا نام تبدیل کرنے میں ناکام"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"کچھ فائلوں کو تبدیل کیا گیا تھا"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> کو <xliff:g id="STORAGE"><i>^3</i></xliff:g> پر <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ڈائرکٹری تک رسائی عطا کریں؟"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> کو <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ڈائرکٹری تک رسائی دیں؟"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> کو اپنے ڈیٹا بشمول <xliff:g id="STORAGE"><i>^2</i></xliff:g> پر موجود تصاویر اور ویڈیوز تک رسائی عطا کریں؟"</string>
<string name="never_ask_again" msgid="4295278542972859268">"دوبارہ نہ پوچھیں"</string>
<string name="allow" msgid="7225948811296386551">"اجازت دیں"</string>
diff --git a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
index dffbba5..2654308 100644
--- a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
+++ b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
@@ -110,7 +110,8 @@
<string name="menu_rename" msgid="7678802479104285353">"Qayta nomlash"</string>
<string name="rename_error" msgid="4203041674883412606">"Hujjatni qayta nomlab bo‘lmadi"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Bir nechta fayllar o‘girildi"</string>
- <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ilovasining <xliff:g id="STORAGE"><i>^3</i></xliff:g> xotirasidagi “<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>” jildiga kirishiga ruxsat berilsinmi?"</string>
+ <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ilovasiga <xliff:g id="STORAGE"><i>^3</i></xliff:g> xotirasidagi “<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>” jildidan foydalanishiga ruxsat berilsinmi?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ilovasiga “<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>” jildidan foydalanishiga ruxsat berilsinmi?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ilovasiga <xliff:g id="STORAGE"><i>^2</i></xliff:g> xotirasidagi ma’lumotlardan, jumladan, rasmlar va videolardan foydalanishiga ruxsat berilsinmi?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Boshqa so‘ralmasin"</string>
<string name="allow" msgid="7225948811296386551">"Ruxsat berish"</string>
diff --git a/packages/DocumentsUI/res/values-vi/strings.xml b/packages/DocumentsUI/res/values-vi/strings.xml
index 127c2d3..9af7db0 100644
--- a/packages/DocumentsUI/res/values-vi/strings.xml
+++ b/packages/DocumentsUI/res/values-vi/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Không đổi được tên tài liệu"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Đã chuyển đổi một số tệp"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Cấp cho <xliff:g id="APPNAME"><b>^1</b></xliff:g> quyền truy cập vào thư mục <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> trong <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Cấp cho <xliff:g id="APPNAME"><b>^1</b></xliff:g> quyền truy cập thư mục <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Cấp cho <xliff:g id="APPNAME"><b>^1</b></xliff:g> quyền truy cập vào dữ liệu của bạn, kể cả ảnh và video trên <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Không hỏi lại"</string>
<string name="allow" msgid="7225948811296386551">"Cho phép"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
index 45d22a3..e3db1a0 100644
--- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"无法重命名文档"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"部分文件已转换成其他格式"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"要授权<xliff:g id="APPNAME"><b>^1</b></xliff:g>访问 <xliff:g id="STORAGE"><i>^3</i></xliff:g>上的“<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>”目录吗?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"要授权<xliff:g id="APPNAME"><b>^1</b></xliff:g>访问<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>目录吗?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"要授权<xliff:g id="APPNAME"><b>^1</b></xliff:g>访问您 <xliff:g id="STORAGE"><i>^2</i></xliff:g>上的数据(包括照片和视频)吗?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"不再询问"</string>
<string name="allow" msgid="7225948811296386551">"允许"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
index 08aefdd..f13a4bd1 100644
--- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"無法重新命名文件"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"部分檔案已轉換成其他格式"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"要為「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」開放 <xliff:g id="STORAGE"><i>^3</i></xliff:g>上的「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」目錄存取權嗎?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"要為「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」開放「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」目錄的存取權嗎?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"要向「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」開放 <xliff:g id="STORAGE"><i>^2</i></xliff:g>上的相片和影片等資料的存取權嗎?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"不要再詢問"</string>
<string name="allow" msgid="7225948811296386551">"允許"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rTW/strings.xml b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
index 90c932c..f8f8282 100644
--- a/packages/DocumentsUI/res/values-zh-rTW/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"無法重新命名文件"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"部分檔案已轉換成其他格式"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"要允許<xliff:g id="APPNAME"><b>^1</b></xliff:g>存取 <xliff:g id="STORAGE"><i>^3</i></xliff:g>上的「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」目錄嗎?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"要允許<xliff:g id="APPNAME"><b>^1</b></xliff:g>存取「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」目錄嗎?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"要允許「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」存取 <xliff:g id="STORAGE"><i>^2</i></xliff:g>上的資料 (包括相片和影片) 嗎?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"不要再詢問"</string>
<string name="allow" msgid="7225948811296386551">"允許"</string>
diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml
index e83bb3d..a0b9f7f 100644
--- a/packages/DocumentsUI/res/values-zu/strings.xml
+++ b/packages/DocumentsUI/res/values-zu/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Yehlulekile ukuqamba kabusha idokhumenti"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Amanye amafayela aguqulelwe"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Nika i-<xliff:g id="APPNAME"><b>^1</b></xliff:g> ukufinyelela ekuqondiseni kwe-<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ku-<xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Nika ukufinyelela kwe-<xliff:g id="APPNAME"><b>^1</b></xliff:g> kwinkomba ye-<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Nikeza i-<xliff:g id="APPNAME"><b>^1</b></xliff:g> ukufinyelela kudatha yakho, okufaka izithombe namavidiyo, ku-<xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Ungaphindi ubuze"</string>
<string name="allow" msgid="7225948811296386551">"Vumela"</string>
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
index b16554c..b0996aa 100644
--- a/packages/DocumentsUI/res/values/styles.xml
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -36,8 +36,6 @@
<item name="android:windowActionBar">false</item>
<item name="android:windowActionModeOverlay">true</item>
<item name="android:windowNoTitle">true</item>
- <item name="android:windowTranslucentStatus">true</item>
- <item name="android:fitsSystemWindows">false</item>
<item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
</style>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 2d051e4..d6c742a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -49,6 +49,7 @@
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
+import android.view.WindowManager;
import android.widget.Spinner;
import com.android.documentsui.SearchViewManager.SearchManagerListener;
@@ -103,6 +104,16 @@
@CallSuper
@Override
public void onCreate(Bundle icicle) {
+ // This flag is being set here as a result of the bug. When the flag was set in the
+ // styles.xml keyboard was messing the layout of dialogs (create dir, rename).
+ // Attempts were made to keep the flag in the main theme and to override it in the dialog
+ // layout xml or to create separate style for dialog and assign it in styles.xml.
+ // None of this brought successful results.
+ // Setting the flag works here most probably because of the timing when it is set. Also the
+ // setting might not affect the dialogs that are created in new windows or it affects them
+ // in the different way that having this in the style.
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+
// Record the time when onCreate is invoked for metric.
mStartTime = new Date().getTime();
@@ -261,6 +272,7 @@
@Override
public boolean onOptionsItemSelected(MenuItem item) {
+ Metrics.logMenuAction(this, item.getItemId());
switch (item.getItemId()) {
case android.R.id.home:
@@ -624,10 +636,12 @@
return true;
}
} else if (keyCode == KeyEvent.KEYCODE_TAB) {
+ Metrics.logKeyboardAction(this, Metrics.ACTION_KEYBOARD_SWITCH_FOCUS);
// Tab toggles focus on the navigation drawer.
toggleNavDrawerFocus();
return true;
} else if (keyCode == KeyEvent.KEYCODE_DEL) {
+ Metrics.logKeyboardAction(this, Metrics.ACTION_KEYBOARD_BACK);
popDir();
return true;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java
index 9005442..5ea6cfa 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java
@@ -69,7 +69,7 @@
final int memoryClassBytes = am.getMemoryClass() * 1024 * 1024;
mRoots = new RootsCache(this);
- mRoots.updateAsync();
+ mRoots.updateAsync(false);
mThumbnails = new ThumbnailCache(memoryClassBytes / 4);
@@ -105,7 +105,7 @@
final String packageName = data.getSchemeSpecificPart();
mRoots.updatePackageAsync(packageName);
} else {
- mRoots.updateAsync();
+ mRoots.updateAsync(true);
}
}
};
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index 68c0c2a..f072011 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -212,19 +212,22 @@
case R.id.menu_create_dir:
assert(canCreateDirectory());
showCreateDirectoryDialog();
- return true;
+ break;
case R.id.menu_new_window:
createNewWindow();
- return true;
+ break;
case R.id.menu_paste_from_clipboard:
DirectoryFragment dir = getDirectoryFragment();
if (dir != null) {
dir.pasteFromClipboard();
}
- return true;
+ break;
+ default:
+ return super.onOptionsItemSelected(item);
}
- return super.onOptionsItemSelected(item);
+ Metrics.logMenuAction(this, item.getItemId());
+ return true;
}
private void createNewWindow() {
@@ -346,18 +349,21 @@
case KeyEvent.KEYCODE_A:
dir = getDirectoryFragment();
if (dir != null) {
+ Metrics.logKeyboardAction(this, Metrics.ACTION_KEYBOARD_SELECT_ALL);
dir.selectAllFiles();
}
return true;
case KeyEvent.KEYCODE_C:
dir = getDirectoryFragment();
if (dir != null) {
+ Metrics.logKeyboardAction(this, Metrics.ACTION_KEYBOARD_COPY);
dir.copySelectedToClipboard();
}
return true;
case KeyEvent.KEYCODE_V:
dir = getDirectoryFragment();
if (dir != null) {
+ Metrics.logKeyboardAction(this, Metrics.ACTION_KEYBOARD_PASTE);
dir.pasteFromClipboard();
}
return true;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Metrics.java b/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
index f1f47c8..05cc7e6 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
@@ -29,6 +29,7 @@
import android.net.Uri;
import android.provider.DocumentsContract;
import android.util.Log;
+import android.view.KeyEvent;
import com.android.documentsui.State.ActionType;
import com.android.documentsui.model.DocumentInfo;
@@ -67,6 +68,10 @@
private static final String COUNT_FILEOP_CANCELED = "docsui_fileop_canceled";
private static final String COUNT_STARTUP_MS = "docsui_startup_ms";
private static final String COUNT_DRAWER_OPENED = "docsui_drawer_opened";
+ private static final String COUNT_DRAG_N_DROP = "docsui_drag_n_drop";
+ private static final String COUNT_SEARCH = "docsui_search";
+ private static final String COUNT_MENU_ACTION = "docsui_menu_action";
+ private static final String COUNT_KEYBOARD_ACTION = "docsui_keyboard_action";
// Indices for bucketing roots in the roots histogram. "Other" is the catch-all index for any
// root that is not explicitly recognized by the Metrics code (see {@link
@@ -196,8 +201,71 @@
@Retention(RetentionPolicy.SOURCE)
public @interface MetricsOpType {}
- // Codes representing different launch actions. These are used for bucketing stats in the
- // COUNT_LAUNCH_ACTION histogram.
+ // Codes representing different provider types. Used for sorting file operations when logging.
+ private static final int PROVIDER_INTRA = 0;
+ private static final int PROVIDER_SYSTEM = 1;
+ private static final int PROVIDER_EXTERNAL = 2;
+
+ @IntDef(flag = false, value = {
+ PROVIDER_INTRA,
+ PROVIDER_SYSTEM,
+ PROVIDER_EXTERNAL
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Provider {}
+
+
+ // Codes representing different menu actions. These are used for bucketing stats in the
+ // COUNT_MENU_ACTION histogram.
+ // Both regular toolbar menu and action mode menu operations are included.
+ // Do not change or rearrange these values, that will break historical data. Only add to the
+ // list.
+ // Do not use negative numbers or zero; clearcut only handles positive integers.
+ private static final int ACTION_MENU_OTHER = 1;
+ private static final int ACTION_MENU_GRID = 2;
+ private static final int ACTION_MENU_LIST = 3;
+ private static final int ACTION_MENU_SORT = 4;
+ private static final int ACTION_MENU_SORT_NAME = 5;
+ private static final int ACTION_MENU_SORT_DATE = 6;
+ private static final int ACTION_MENU_SORT_SIZE = 7;
+ private static final int ACTION_MENU_SEARCH = 8;
+ private static final int ACTION_MENU_SHOW_SIZE = 9;
+ private static final int ACTION_MENU_SETTINGS = 10;
+ private static final int ACTION_MENU_COPY_TO = 11;
+ private static final int ACTION_MENU_MOVE_TO = 12;
+ private static final int ACTION_MENU_DELETE = 13;
+ private static final int ACTION_MENU_RENAME = 14;
+ private static final int ACTION_MENU_CREATE_DIR = 15;
+ private static final int ACTION_MENU_SELECT_ALL = 16;
+ private static final int ACTION_MENU_SHARE = 17;
+ private static final int ACTION_MENU_OPEN = 18;
+ private static final int ACTION_MENU_ADVANCED = 19;
+
+ @IntDef(flag = false, value = {
+ ACTION_MENU_OTHER,
+ ACTION_MENU_GRID,
+ ACTION_MENU_LIST,
+ ACTION_MENU_SORT,
+ ACTION_MENU_SORT_NAME,
+ ACTION_MENU_SORT_DATE,
+ ACTION_MENU_SORT_SIZE,
+ ACTION_MENU_SHOW_SIZE,
+ ACTION_MENU_SETTINGS,
+ ACTION_MENU_COPY_TO,
+ ACTION_MENU_MOVE_TO,
+ ACTION_MENU_DELETE,
+ ACTION_MENU_RENAME,
+ ACTION_MENU_CREATE_DIR,
+ ACTION_MENU_SELECT_ALL,
+ ACTION_MENU_SHARE,
+ ACTION_MENU_OPEN,
+ ACTION_MENU_ADVANCED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface MenuAction {}
+
+ // Codes representing different menu actions. These are used for bucketing stats in the
+ // COUNT_MENU_ACTION histogram.
// Do not change or rearrange these values, that will break historical data. Only add to the
// list.
// Do not use negative numbers or zero; clearcut only handles positive integers.
@@ -223,18 +291,30 @@
@Retention(RetentionPolicy.SOURCE)
public @interface MetricsAction {}
- // Codes representing different provider types. Used for sorting file operations when logging.
- private static final int PROVIDER_INTRA = 0;
- private static final int PROVIDER_SYSTEM = 1;
- private static final int PROVIDER_EXTERNAL = 2;
+ // Codes representing different keyboard shortcut triggered actions. These are used for
+ // bucketing stats in the COUNT_KEYBOARD_ACTION histogram.
+ // Do not change or rearrange these values, that will break historical data. Only add to the
+ // list.
+ // Do not use negative numbers or zero; clearcut only handles positive integers.
+ public static final int ACTION_KEYBOARD_OTHER = 1;
+ public static final int ACTION_KEYBOARD_PASTE = 2;
+ public static final int ACTION_KEYBOARD_COPY = 3;
+ public static final int ACTION_KEYBOARD_DELETE = 4;
+ public static final int ACTION_KEYBOARD_SELECT_ALL = 5;
+ public static final int ACTION_KEYBOARD_BACK = 6;
+ public static final int ACTION_KEYBOARD_SWITCH_FOCUS = 7;
- @IntDef(flag = true, value = {
- PROVIDER_INTRA,
- PROVIDER_SYSTEM,
- PROVIDER_EXTERNAL
+ @IntDef(flag = false, value = {
+ ACTION_KEYBOARD_OTHER,
+ ACTION_KEYBOARD_PASTE,
+ ACTION_KEYBOARD_COPY,
+ ACTION_KEYBOARD_DELETE,
+ ACTION_KEYBOARD_SELECT_ALL,
+ ACTION_KEYBOARD_BACK,
+ ACTION_KEYBOARD_SWITCH_FOCUS
})
@Retention(RetentionPolicy.SOURCE)
- public @interface Provider {}
+ public @interface KeyboardAction {}
// Codes representing different actions to open the drawer. They are used for bucketing stats in
// the COUNT_DRAWER_OPENED histogram.
@@ -440,6 +520,16 @@
}
/**
+ * Logs keyboard shortcut actions. Since keyboard shortcuts have their corresponding menu items,
+ * they are identified by menu item resource id for convenience.
+ * @param context
+ * @param keyCode
+ */
+ public static void logKeyboardAction(Context context, @KeyboardAction int action) {
+ logHistogram(context, COUNT_KEYBOARD_ACTION, action);
+ }
+
+ /**
* Logs startup time in milliseconds.
* @param context
* @param startupMs Startup time in milliseconds.
@@ -448,6 +538,25 @@
logHistogram(context, COUNT_STARTUP_MS, startupMs);
}
+ /**
+ * Logs a drag and drop action. Call this when the user drops the content triggering copy.
+ * operation.
+ *
+ * @param context
+ */
+ public static void logDragNDrop(Context context) {
+ logCount(context, COUNT_DRAG_N_DROP);
+ }
+
+ /**
+ * Logs a search. Call this when the search operation is finished.
+ *
+ * @param context
+ */
+ public static void logSearch(Context context) {
+ logCount(context, COUNT_SEARCH);
+ }
+
private static void logInterProviderFileOps(
Context context,
String histogram,
@@ -568,6 +677,74 @@
}
/**
+ * Logs menu action that was selected by user.
+ * @param context
+ * @param id Resource id of the menu item.
+ */
+ public static void logMenuAction(Context context, int id) {
+ @MenuAction int menuAction = ACTION_MENU_OTHER;
+ switch (id) {
+ case R.id.menu_grid:
+ menuAction = ACTION_MENU_GRID;
+ break;
+ case R.id.menu_list:
+ menuAction = ACTION_MENU_LIST;
+ break;
+ case R.id.menu_sort:
+ menuAction = ACTION_MENU_SORT;
+ break;
+ case R.id.menu_sort_name:
+ menuAction = ACTION_MENU_SORT_NAME;
+ break;
+ case R.id.menu_sort_date:
+ menuAction = ACTION_MENU_SORT_DATE;
+ break;
+ case R.id.menu_sort_size:
+ menuAction = ACTION_MENU_SORT_SIZE;
+ break;
+ case R.id.menu_search:
+ menuAction = ACTION_MENU_SEARCH;
+ break;
+ case R.id.menu_file_size:
+ menuAction = ACTION_MENU_SHOW_SIZE;
+ break;
+ case R.id.menu_settings:
+ menuAction = ACTION_MENU_SETTINGS;
+ break;
+ case R.id.menu_copy_to:
+ menuAction = ACTION_MENU_COPY_TO;
+ break;
+ case R.id.menu_move_to:
+ menuAction = ACTION_MENU_MOVE_TO;
+ break;
+ case R.id.menu_delete:
+ menuAction = ACTION_MENU_DELETE;
+ break;
+ case R.id.menu_rename:
+ menuAction = ACTION_MENU_RENAME;
+ break;
+ case R.id.menu_create_dir:
+ menuAction = ACTION_MENU_CREATE_DIR;
+ break;
+ case R.id.menu_select_all:
+ menuAction = ACTION_MENU_SELECT_ALL;
+ break;
+ case R.id.menu_share:
+ menuAction = ACTION_MENU_SHARE;
+ break;
+ case R.id.menu_open:
+ menuAction = ACTION_MENU_OPEN;
+ break;
+ case R.id.menu_advanced:
+ menuAction = ACTION_MENU_ADVANCED;
+ break;
+ default:
+ break;
+ }
+ logHistogram(context, COUNT_MENU_ACTION, menuAction);
+ }
+
+ /**
* Internal method for making a MetricsLogger.count call. Increments the given counter by 1.
*
* @param context
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index 09fadc9..594e02f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -122,7 +122,7 @@
/**
* Gather roots from all known storage providers.
*/
- public void updateAsync() {
+ public void updateAsync(boolean forceRefreshAll) {
// NOTE: This method is called when the UI language changes.
// For that reason we update our RecentsRoot to reflect
@@ -139,14 +139,15 @@
| Root.FLAG_SUPPORTS_CREATE));
assert(mRecentsRoot.availableBytes == -1);
- new UpdateTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ new UpdateTask(forceRefreshAll, null)
+ .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
/**
* Gather roots from storage providers belonging to given package name.
*/
public void updatePackageAsync(String packageName) {
- new UpdateTask(packageName).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ new UpdateTask(false, packageName).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
/**
@@ -223,23 +224,22 @@
}
private class UpdateTask extends AsyncTask<Void, Void, Void> {
+ private final boolean mForceRefreshAll;
private final String mForceRefreshPackage;
private final Multimap<String, RootInfo> mTaskRoots = ArrayListMultimap.create();
private final HashSet<String> mTaskStoppedAuthorities = new HashSet<>();
/**
- * Update all roots.
+ * Create task to update roots cache.
+ *
+ * @param forceRefreshAll when true, all previously cached values for
+ * all packages should be ignored.
+ * @param forceRefreshPackage when non-null, all previously cached
+ * values for this specific package should be ignored.
*/
- public UpdateTask() {
- this(null);
- }
-
- /**
- * Force update roots belonging to given package name. Other roots will
- * be copied from cached {@link #mRoots} values.
- */
- public UpdateTask(String forceRefreshPackage) {
+ public UpdateTask(boolean forceRefreshAll, String forceRefreshPackage) {
+ mForceRefreshAll = forceRefreshAll;
mForceRefreshPackage = forceRefreshPackage;
}
@@ -247,14 +247,6 @@
protected Void doInBackground(Void... params) {
final long start = SystemClock.elapsedRealtime();
- if (mForceRefreshPackage != null) {
- // We must have previously cached values to fill in non-matching
- // packages, so wait around for successful first load.
- if (!waitForFirstLoad()) {
- return null;
- }
- }
-
mTaskRoots.put(mRecentsRoot.authority, mRecentsRoot);
final ContentResolver resolver = mContext.getContentResolver();
@@ -300,7 +292,8 @@
return;
}
- final boolean forceRefresh = Objects.equals(mForceRefreshPackage, info.packageName);
+ final boolean forceRefresh = mForceRefreshAll
+ || Objects.equals(info.packageName, mForceRefreshPackage);
mTaskRoots.putAll(info.authority, loadRootsForAuthority(mContext.getContentResolver(),
info.authority, forceRefresh));
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SearchViewManager.java b/packages/DocumentsUI/src/com/android/documentsui/SearchViewManager.java
index 11b8891..945ed34 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SearchViewManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SearchViewManager.java
@@ -185,6 +185,9 @@
if(mFullBar) {
Menu menu = mActionBar.getMenu();
menu.setGroupVisible(R.id.group_hide_when_searching, false);
+ } else {
+ // If search in full-bar mode it will be logged in FilesActivity#onOptionsItemSelected
+ Metrics.logMenuAction(mActionBar.getContext(), R.id.menu_search);
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 73ce0e1..c2bb4eb 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -85,6 +85,7 @@
import com.android.documentsui.Events.MotionInputEvent;
import com.android.documentsui.Menus;
import com.android.documentsui.MessageBar;
+import com.android.documentsui.Metrics;
import com.android.documentsui.R;
import com.android.documentsui.RecentsLoader;
import com.android.documentsui.RootsCache;
@@ -105,6 +106,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
import java.util.Objects;
@@ -594,6 +596,7 @@
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+ Metrics.logMenuAction(getContext(), item.getItemId());
Selection selection = mSelectionManager.getSelection(new Selection());
@@ -1061,8 +1064,19 @@
}
public void selectAllFiles() {
+ // Exclude disabled files
+ List<String> enabled = new ArrayList<String>();
+ for (String id : mAdapter.getModelIds()) {
+ Cursor cursor = getModel().getItem(id);
+ String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+ int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
+ if (isDocumentEnabled(docMimeType, docFlags)) {
+ enabled.add(id);
+ }
+ }
+
// Only select things currently visible in the adapter.
- boolean changed = mSelectionManager.setItemsSelected(mAdapter.getModelIds(), true);
+ boolean changed = mSelectionManager.setItemsSelected(enabled, true);
if (changed) {
updateDisplayState();
}
@@ -1124,6 +1138,7 @@
if (Objects.equals(src, dst)) {
return false;
}
+ Metrics.logDragNDrop(getContext());
copyFromClipData(event.getClipData(), dst);
return true;
}
@@ -1336,6 +1351,7 @@
// This has to be handled here instead of in a keyboard shortcut, because
// keyboard shortcuts all have to be modified with the 'Ctrl' key.
if (mSelectionManager.hasSelection()) {
+ Metrics.logKeyboardAction(getContext(), Metrics.ACTION_KEYBOARD_DELETE);
deleteDocuments(mSelectionManager.getSelection());
}
// Always handle the key, even if there was nothing to delete. This is a
@@ -1622,6 +1638,9 @@
@Override
public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) {
if (!isAdded()) return;
+ if (mSearchMode) {
+ Metrics.logSearch(getContext());
+ }
State state = getDisplayState();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
index faa8e38..016cc9e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
@@ -148,11 +148,15 @@
MenuItem share = menu.findItem(R.id.menu_share);
MenuItem delete = menu.findItem(R.id.menu_delete);
MenuItem rename = menu.findItem(R.id.menu_rename);
+ MenuItem selectAll = menu.findItem(R.id.menu_select_all);
open.setVisible(true);
share.setVisible(false);
delete.setVisible(false);
rename.setVisible(false);
+ selectAll.setVisible(mState.allowMultiple);
+
+ Menus.disableHiddenItems(menu);
}
@Override
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/bots/UiBot.java b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/UiBot.java
index 5b53caf..4c8dc00 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/bots/UiBot.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/UiBot.java
@@ -162,7 +162,9 @@
}
UiObject findSearchViewIcon() {
- return findObject("com.android.documentsui:id/menu_search", "android:id/search_button");
+ return mContext.getResources().getBoolean(R.bool.full_bar_search_view)
+ ? findObject("com.android.documentsui:id/menu_search")
+ : findObject("com.android.documentsui:id/menu_search", "android:id/search_button");
}
UiObject findActionModeBar() {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
index 454221a..2b549f1 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -77,6 +77,7 @@
case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
+ case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
return SecurityMode.Password;
case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
diff --git a/packages/PrintServiceRecommendationService/res/values/strings.xml b/packages/PrintServiceRecommendationService/res/values/strings.xml
index 83d3800..07d0004 100644
--- a/packages/PrintServiceRecommendationService/res/values/strings.xml
+++ b/packages/PrintServiceRecommendationService/res/values/strings.xml
@@ -23,7 +23,7 @@
<string name="plugin_vendor_brother">Brother</string>
<string name="plugin_vendor_canon">Canon</string>
<string name="plugin_vendor_xerox">Xerox</string>
- <string name="plugin_vendor_samsung">Samsung Electorics</string>
+ <string name="plugin_vendor_samsung">Samsung Electronics</string>
<string name="plugin_vendor_epson">Epson</string>
<string name="plugin_vendor_konika_minolta">Konika Minolta</string>
<string name="plugin_vendor_fuji">Fuji</string>
diff --git a/packages/PrintServiceRecommendationService/res/xml/vendorconfigs.xml b/packages/PrintServiceRecommendationService/res/xml/vendorconfigs.xml
index fda2768..119943c 100644
--- a/packages/PrintServiceRecommendationService/res/xml/vendorconfigs.xml
+++ b/packages/PrintServiceRecommendationService/res/xml/vendorconfigs.xml
@@ -46,7 +46,7 @@
<vendor>
<name>@string/plugin_vendor_canon</name>
- <package>com.xerox.printservice</package>
+ <package>jp.co.canon.android.printservice.plugin</package>
<mdns-names>
<mdns-name>Canon</mdns-name>
</mdns-names>
@@ -54,7 +54,7 @@
<vendor>
<name>@string/plugin_vendor_xerox</name>
- <package>jp.co.canon.android.printservice.plugin</package>
+ <package>com.xerox.printservice</package>
<mdns-names>
<mdns-name>Xerox</mdns-name>
</mdns-names>
diff --git a/packages/PrintSpooler/res/values-af/strings.xml b/packages/PrintSpooler/res/values-af/strings.xml
index 0224c6c..fa5ec3f 100644
--- a/packages/PrintSpooler/res/values-af/strings.xml
+++ b/packages/PrintSpooler/res/values-af/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Aanbevole dienste"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Gedeaktiveerde dienste"</string>
<string name="all_services_title" msgid="5578662754874906455">"Alle dienste"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Installeer om <xliff:g id="COUNT_1">%1$s</xliff:g> drukkers te ontdek</item>
+ <item quantity="one">Installeer om <xliff:g id="COUNT_0">%1$s</xliff:g> drukker ontdek</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Druk tans <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Kanselleer tans <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Drukkerfout by <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-am/strings.xml b/packages/PrintSpooler/res/values-am/strings.xml
index 98255d4..5ada8d3 100644
--- a/packages/PrintSpooler/res/values-am/strings.xml
+++ b/packages/PrintSpooler/res/values-am/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"የሚመከሩ አገልግሎቶች"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"የተሰናከሉ አገልግሎቶች"</string>
<string name="all_services_title" msgid="5578662754874906455">"ሁሉም አገልግሎቶች"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> አታሚዎች ለማግኘት ይጫኑ</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> አታሚዎች ለማግኘት ይጫኑ</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ን በማተም ላይ"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ን በመተው ላይ"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"የአታሚ ስህተት <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ar/strings.xml b/packages/PrintSpooler/res/values-ar/strings.xml
index 5f0255c..1208298 100644
--- a/packages/PrintSpooler/res/values-ar/strings.xml
+++ b/packages/PrintSpooler/res/values-ar/strings.xml
@@ -76,6 +76,14 @@
<string name="recommended_services_title" msgid="3799434882937956924">"الخدمات الموصى بها"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"الخدمات المعطَّلة"</string>
<string name="all_services_title" msgid="5578662754874906455">"جميع الخدمات"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="zero">التثبيت لاستكشاف <xliff:g id="COUNT_1">%1$s</xliff:g> طابعات</item>
+ <item quantity="two">التثبيت لاستكشاف طابعتين (<xliff:g id="COUNT_1">%1$s</xliff:g>)</item>
+ <item quantity="few">التثبيت لاستكشاف <xliff:g id="COUNT_1">%1$s</xliff:g> طابعات</item>
+ <item quantity="many">التثبيت لاستكشاف <xliff:g id="COUNT_1">%1$s</xliff:g> طابعة</item>
+ <item quantity="other">التثبيت لاستكشاف <xliff:g id="COUNT_1">%1$s</xliff:g> طابعات</item>
+ <item quantity="one">التثبيت لاستكشاف <xliff:g id="COUNT_0">%1$s</xliff:g> طابعة</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"جارٍ طباعة <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"جارٍ إلغاء <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"خطا في الطابعة <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-az-rAZ/strings.xml b/packages/PrintSpooler/res/values-az-rAZ/strings.xml
index b5dfaf8..4404aad 100644
--- a/packages/PrintSpooler/res/values-az-rAZ/strings.xml
+++ b/packages/PrintSpooler/res/values-az-rAZ/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Tövsiyə olunan xidmətlər"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Deaktiv edilmiş xidmətlər"</string>
<string name="all_services_title" msgid="5578662754874906455">"Bütün xidmətlər"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printeri kəşf etmək üçün quraşdırın</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printeri kəşf etmək üçün quraşdırın</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> çap edilir"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ləğv edilir"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printer xətası <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
index 2ac8002..50ce1f9 100644
--- a/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
+++ b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
@@ -73,6 +73,11 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Preporučene usluge"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Onemogućene usluge"</string>
<string name="all_services_title" msgid="5578662754874906455">"Sve usluge"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Instalirajte da biste otkrili <xliff:g id="COUNT_1">%1$s</xliff:g> štampač</item>
+ <item quantity="few">Instalirajte da biste otkrili <xliff:g id="COUNT_1">%1$s</xliff:g> štampača</item>
+ <item quantity="other">Instalirajte da biste otkrili <xliff:g id="COUNT_1">%1$s</xliff:g> štampača</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Štampa se <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Otkazuje se <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Greška štampača <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-be-rBY/strings.xml b/packages/PrintSpooler/res/values-be-rBY/strings.xml
index 13d573e..c264f92 100644
--- a/packages/PrintSpooler/res/values-be-rBY/strings.xml
+++ b/packages/PrintSpooler/res/values-be-rBY/strings.xml
@@ -74,6 +74,12 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Рэкамендаваныя службы"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Адключаныя службы"</string>
<string name="all_services_title" msgid="5578662754874906455">"Усе службы"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Усталюйце, каб знайсці <xliff:g id="COUNT_1">%1$s</xliff:g> прынтар</item>
+ <item quantity="few">Усталюйце, каб знайсці <xliff:g id="COUNT_1">%1$s</xliff:g> прынтары</item>
+ <item quantity="many">Усталюйце, каб знайсці <xliff:g id="COUNT_1">%1$s</xliff:g> прынтараў</item>
+ <item quantity="other">Усталюйце, каб знайсці <xliff:g id="COUNT_1">%1$s</xliff:g> прынтара</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Друк <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Скасоўваецца <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Памылка друку <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-bg/strings.xml b/packages/PrintSpooler/res/values-bg/strings.xml
index 73c51e9..3dd6ec5 100644
--- a/packages/PrintSpooler/res/values-bg/strings.xml
+++ b/packages/PrintSpooler/res/values-bg/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Препоръчителни услуги"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Деактивирани услуги"</string>
<string name="all_services_title" msgid="5578662754874906455">"Всички услуги"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Инсталирайте, за да бъдат открити <xliff:g id="COUNT_1">%1$s</xliff:g> принтера</item>
+ <item quantity="one">Инсталирайте, за да бъде открит <xliff:g id="COUNT_0">%1$s</xliff:g> принтер</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"„<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“ се отпечатва"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"„<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“ се анулира"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Грешка в принтера при „<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“"</string>
diff --git a/packages/PrintSpooler/res/values-bn-rBD/strings.xml b/packages/PrintSpooler/res/values-bn-rBD/strings.xml
index 25b4660..3789f21 100644
--- a/packages/PrintSpooler/res/values-bn-rBD/strings.xml
+++ b/packages/PrintSpooler/res/values-bn-rBD/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"প্রস্তাবিত পরিষেবাগুলি"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"অক্ষম করা পরিষেবাগুলি"</string>
<string name="all_services_title" msgid="5578662754874906455">"সমস্ত পরিষেবা"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g>টি মুদ্রক খুঁজে পেতে ইনস্টল করুন</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g>টি মুদ্রক খুঁজে পেতে ইনস্টল করুন</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> প্রিন্ট করা হচ্ছে"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> বাতিল করা হচ্ছে"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> মুদ্রক ত্রুটি"</string>
diff --git a/packages/PrintSpooler/res/values-bs-rBA/strings.xml b/packages/PrintSpooler/res/values-bs-rBA/strings.xml
index 9a17707..c3c9bb33 100644
--- a/packages/PrintSpooler/res/values-bs-rBA/strings.xml
+++ b/packages/PrintSpooler/res/values-bs-rBA/strings.xml
@@ -73,6 +73,11 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Preporučene usluge"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Isključene usluge"</string>
<string name="all_services_title" msgid="5578662754874906455">"Sve usluge"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one"> Instaliraj da pronađeš <xliff:g id="COUNT_1">%1$s</xliff:g> štampač</item>
+ <item quantity="few"> Instaliraj da pronađeš <xliff:g id="COUNT_1">%1$s</xliff:g> štampača</item>
+ <item quantity="other"> Instaliraj da pronađeš <xliff:g id="COUNT_1">%1$s</xliff:g> štampača</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Štampa se <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Otkazivanje <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Greška pri štampanju <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ca/strings.xml b/packages/PrintSpooler/res/values-ca/strings.xml
index a1df406..f65a63c 100644
--- a/packages/PrintSpooler/res/values-ca/strings.xml
+++ b/packages/PrintSpooler/res/values-ca/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Serveis recomanats"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Serveis desactivats"</string>
<string name="all_services_title" msgid="5578662754874906455">"Tots els serveis"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Instal·la\'l per detectar <xliff:g id="COUNT_1">%1$s</xliff:g> impressores</item>
+ <item quantity="one">Instal·la\'l per detectar <xliff:g id="COUNT_0">%1$s</xliff:g> impressora</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"S\'està imprimint <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"S\'està cancel·lant <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Error d\'impressora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-cs/strings.xml b/packages/PrintSpooler/res/values-cs/strings.xml
index 55fb21b..9bfa271 100644
--- a/packages/PrintSpooler/res/values-cs/strings.xml
+++ b/packages/PrintSpooler/res/values-cs/strings.xml
@@ -74,6 +74,12 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Doporučené služby"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Deaktivované služby"</string>
<string name="all_services_title" msgid="5578662754874906455">"Všechny služby"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="few">Instalací objevíte <xliff:g id="COUNT_1">%1$s</xliff:g> tiskárny</item>
+ <item quantity="many">Instalací objevíte <xliff:g id="COUNT_1">%1$s</xliff:g> tiskárny</item>
+ <item quantity="other">Instalací objevíte <xliff:g id="COUNT_1">%1$s</xliff:g> tiskáren</item>
+ <item quantity="one">Instalací objevíte <xliff:g id="COUNT_0">%1$s</xliff:g> tiskárnu</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Tisk úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Rušení úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Chyba tiskárny u úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-da/strings.xml b/packages/PrintSpooler/res/values-da/strings.xml
index 49417bd..75a0b56 100644
--- a/packages/PrintSpooler/res/values-da/strings.xml
+++ b/packages/PrintSpooler/res/values-da/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Anbefalede tjenester"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Deaktiverede tjenester"</string>
<string name="all_services_title" msgid="5578662754874906455">"Alle tjenester"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Installer for at finde <xliff:g id="COUNT_1">%1$s</xliff:g> printer</item>
+ <item quantity="other">Installer for at finde <xliff:g id="COUNT_1">%1$s</xliff:g> printere</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> udskrives"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> annulleres"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Udskriften <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> mislykkedes"</string>
diff --git a/packages/PrintSpooler/res/values-de/strings.xml b/packages/PrintSpooler/res/values-de/strings.xml
index cb7aeee..8c6181d 100644
--- a/packages/PrintSpooler/res/values-de/strings.xml
+++ b/packages/PrintSpooler/res/values-de/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Empfohlene Dienste"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Deaktivierte Dienste"</string>
<string name="all_services_title" msgid="5578662754874906455">"Alle Dienste"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Installieren, um <xliff:g id="COUNT_1">%1$s</xliff:g> Drucker zu erkennen</item>
+ <item quantity="one">Installieren, um <xliff:g id="COUNT_0">%1$s</xliff:g> Drucker zu erkennen</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> wird gedruckt..."</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> wird abgebrochen..."</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Druckerfehler <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-el/strings.xml b/packages/PrintSpooler/res/values-el/strings.xml
index 4441ea2..31d3f83 100644
--- a/packages/PrintSpooler/res/values-el/strings.xml
+++ b/packages/PrintSpooler/res/values-el/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Προτεινόμενες υπηρεσίες"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Υπηρεσίες για άτομα με αναπηρία"</string>
<string name="all_services_title" msgid="5578662754874906455">"Όλες οι υπηρεσίες"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Κάντε εγκατάσταση για να ανακαλύψετε <xliff:g id="COUNT_1">%1$s</xliff:g> εκτυπωτές</item>
+ <item quantity="one">Κάντε εγκατάσταση για να ανακαλύψετε <xliff:g id="COUNT_0">%1$s</xliff:g> εκτυπωτή</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Εκτύπωση <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Ακύρωση <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Σφάλμα εκτυπωτή <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-en-rAU/strings.xml b/packages/PrintSpooler/res/values-en-rAU/strings.xml
index f8b6265..5e32ae4 100644
--- a/packages/PrintSpooler/res/values-en-rAU/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rAU/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Recommended services"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Disabled services"</string>
<string name="all_services_title" msgid="5578662754874906455">"All services"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
+ <item quantity="one">Install to discover <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Printing <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelling <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printer error <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-en-rGB/strings.xml b/packages/PrintSpooler/res/values-en-rGB/strings.xml
index f8b6265..5e32ae4 100644
--- a/packages/PrintSpooler/res/values-en-rGB/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rGB/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Recommended services"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Disabled services"</string>
<string name="all_services_title" msgid="5578662754874906455">"All services"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
+ <item quantity="one">Install to discover <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Printing <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelling <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printer error <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-en-rIN/strings.xml b/packages/PrintSpooler/res/values-en-rIN/strings.xml
index f8b6265..5e32ae4 100644
--- a/packages/PrintSpooler/res/values-en-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rIN/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Recommended services"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Disabled services"</string>
<string name="all_services_title" msgid="5578662754874906455">"All services"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
+ <item quantity="one">Install to discover <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Printing <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelling <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printer error <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-es-rUS/strings.xml b/packages/PrintSpooler/res/values-es-rUS/strings.xml
index 8d55597..a6a9f07 100644
--- a/packages/PrintSpooler/res/values-es-rUS/strings.xml
+++ b/packages/PrintSpooler/res/values-es-rUS/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Servicios recomendados"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Servicios inhabilitados"</string>
<string name="all_services_title" msgid="5578662754874906455">"Todos los servicios"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Instala para ver <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item>
+ <item quantity="one">Instala para ver <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Imprimiendo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Error de impresora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-es/strings.xml b/packages/PrintSpooler/res/values-es/strings.xml
index 7d08a0e..4f6731d 100644
--- a/packages/PrintSpooler/res/values-es/strings.xml
+++ b/packages/PrintSpooler/res/values-es/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Servicios recomendados"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Servicios inhabilitados"</string>
<string name="all_services_title" msgid="5578662754874906455">"Todos los servicios"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Instalar para descubrir <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item>
+ <item quantity="one">Instalar para descubrir <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Imprimiendo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Error de impresora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-et-rEE/strings.xml b/packages/PrintSpooler/res/values-et-rEE/strings.xml
index 09da3e0..3d0516c 100644
--- a/packages/PrintSpooler/res/values-et-rEE/strings.xml
+++ b/packages/PrintSpooler/res/values-et-rEE/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Soovitatud teenused"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Keelatud teenused"</string>
<string name="all_services_title" msgid="5578662754874906455">"Kõik teenused"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Installige <xliff:g id="COUNT_1">%1$s</xliff:g> printeri avastamiseks</item>
+ <item quantity="one">Installige <xliff:g id="COUNT_0">%1$s</xliff:g> printeri avastamiseks</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Prinditöö <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> printimine"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Prinditöö <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> tühistamine"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printeri viga: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-eu-rES/strings.xml b/packages/PrintSpooler/res/values-eu-rES/strings.xml
index 6b760b4..c56692f 100644
--- a/packages/PrintSpooler/res/values-eu-rES/strings.xml
+++ b/packages/PrintSpooler/res/values-eu-rES/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Gomendatutako zerbitzuak"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Desgaitutako zerbitzuak"</string>
<string name="all_services_title" msgid="5578662754874906455">"Zerbitzu guztiak"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Instalatu <xliff:g id="COUNT_1">%1$s</xliff:g> inprimagailu aurkitzeko</item>
+ <item quantity="one">Instalatu <xliff:g id="COUNT_0">%1$s</xliff:g> inprimagailu aurkitzeko</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> inprimatzen"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> bertan behera uzten"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Errorea <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> inprimatzean"</string>
diff --git a/packages/PrintSpooler/res/values-fa/strings.xml b/packages/PrintSpooler/res/values-fa/strings.xml
index fa105d5..8a6c0dd 100644
--- a/packages/PrintSpooler/res/values-fa/strings.xml
+++ b/packages/PrintSpooler/res/values-fa/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"خدمات توصیهشده"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"خدمات غیرفعال"</string>
<string name="all_services_title" msgid="5578662754874906455">"همه خدمات"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">نصب کنید تا <xliff:g id="COUNT_1">%1$s</xliff:g> چاپگر را پیدا کنید</item>
+ <item quantity="other">نصب کنید تا <xliff:g id="COUNT_1">%1$s</xliff:g> چاپگر را پیدا کنید</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"در حال چاپ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"در حال لغو <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"خطای چاپگر <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-fi/strings.xml b/packages/PrintSpooler/res/values-fi/strings.xml
index cf051f8..3d6897d 100644
--- a/packages/PrintSpooler/res/values-fi/strings.xml
+++ b/packages/PrintSpooler/res/values-fi/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Suositellut palvelut"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Käytöstä poistetut palvelut"</string>
<string name="all_services_title" msgid="5578662754874906455">"Kaikki palvelut"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Asentamalla voit löytää <xliff:g id="COUNT_1">%1$s</xliff:g> tulostinta.</item>
+ <item quantity="one">Asentamalla voit löytää <xliff:g id="COUNT_0">%1$s</xliff:g> tulostimen.</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Tulostetaan <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Peruutetaan työ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Tulostinvirhe työlle <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-fr-rCA/strings.xml b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
index 11d2875..6c9539a 100644
--- a/packages/PrintSpooler/res/values-fr-rCA/strings.xml
+++ b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Services recommandés"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Services désactivés"</string>
<string name="all_services_title" msgid="5578662754874906455">"Tous les services"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimante</item>
+ <item quantity="other">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimantes</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Impression de <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> en cours…"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Annulation de « <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> »…"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Erreur impression : « <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> »"</string>
diff --git a/packages/PrintSpooler/res/values-fr/strings.xml b/packages/PrintSpooler/res/values-fr/strings.xml
index 6b89281..64add68 100644
--- a/packages/PrintSpooler/res/values-fr/strings.xml
+++ b/packages/PrintSpooler/res/values-fr/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Services recommandés"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Services désactivés"</string>
<string name="all_services_title" msgid="5578662754874906455">"Tous les services"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimante</item>
+ <item quantity="other">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimantes</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Impression de \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" en cours…"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Annulation de \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" en cours…"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Erreur impression pour \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\""</string>
diff --git a/packages/PrintSpooler/res/values-gl-rES/strings.xml b/packages/PrintSpooler/res/values-gl-rES/strings.xml
index 7ddc9f8..099159d 100644
--- a/packages/PrintSpooler/res/values-gl-rES/strings.xml
+++ b/packages/PrintSpooler/res/values-gl-rES/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Servizos recomendados"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Servizos desactivados"</string>
<string name="all_services_title" msgid="5578662754874906455">"Todos os servizos"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Instala o servizo para atopar <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item>
+ <item quantity="one">Instala o servizo para atopar <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Imprimindo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Erro da impresora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-gu-rIN/strings.xml b/packages/PrintSpooler/res/values-gu-rIN/strings.xml
index 6a7e0df..b42fdab 100644
--- a/packages/PrintSpooler/res/values-gu-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-gu-rIN/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"ભલામણ કરેલી સેવાઓ"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"અક્ષમ કરેલી સેવાઓ"</string>
<string name="all_services_title" msgid="5578662754874906455">"બધી સેવાઓ"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> પ્રિન્ટરની શોધ કરવા માટે ઇન્સ્ટૉલ કરો</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> પ્રિન્ટરની શોધ કરવા માટે ઇન્સ્ટૉલ કરો</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> છાપી રહ્યાં છે"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ને રદ કરી રહ્યું છે"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"પ્રિન્ટર ભૂલ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-hi/strings.xml b/packages/PrintSpooler/res/values-hi/strings.xml
index 377dc62..507754a0 100644
--- a/packages/PrintSpooler/res/values-hi/strings.xml
+++ b/packages/PrintSpooler/res/values-hi/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"सुझाई गई सेवाएं"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"अक्षम सेवाएं"</string>
<string name="all_services_title" msgid="5578662754874906455">"सभी सेवाएं"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर खोजने के लिए इंस्टॉल करें</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर खोजने के लिए इंस्टॉल करें</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> प्रिंट हो रहा है"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> रद्द हो रहा है"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिंटर त्रुटि <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-hr/strings.xml b/packages/PrintSpooler/res/values-hr/strings.xml
index 8550be4..92c97ea 100644
--- a/packages/PrintSpooler/res/values-hr/strings.xml
+++ b/packages/PrintSpooler/res/values-hr/strings.xml
@@ -73,6 +73,11 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Preporučene usluge"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Onemogućene usluge"</string>
<string name="all_services_title" msgid="5578662754874906455">"Sve usluge"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Instalirajte da biste pronašli <xliff:g id="COUNT_1">%1$s</xliff:g> pisač</item>
+ <item quantity="few">Instalirajte da biste pronašli <xliff:g id="COUNT_1">%1$s</xliff:g> pisača</item>
+ <item quantity="other">Instalirajte da biste pronašli <xliff:g id="COUNT_1">%1$s</xliff:g> pisača</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Ispisivanje <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Otkazivanje zadatka <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Pogreška pisača <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-hu/strings.xml b/packages/PrintSpooler/res/values-hu/strings.xml
index 20789a3..a2e53db 100644
--- a/packages/PrintSpooler/res/values-hu/strings.xml
+++ b/packages/PrintSpooler/res/values-hu/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Javasolt szolgáltatások"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Letiltott szolgáltatások"</string>
<string name="all_services_title" msgid="5578662754874906455">"Minden szolgáltatás"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Telepítés <xliff:g id="COUNT_1">%1$s</xliff:g> nyomtató felfedezéséhez</item>
+ <item quantity="one">Telepítés <xliff:g id="COUNT_0">%1$s</xliff:g> nyomtató felfedezéséhez</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"A(z) <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> nyomtatása"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"A(z) <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> törlése"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Nyomtatási hiba: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-hy-rAM/strings.xml b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
index 8950338..e26c244 100644
--- a/packages/PrintSpooler/res/values-hy-rAM/strings.xml
+++ b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Խորհուրդ տրվող ծառայությունները"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Կասեցված ծառայությունները"</string>
<string name="all_services_title" msgid="5578662754874906455">"Բոլոր ծառայությունները"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Տեղադրեք՝ <xliff:g id="COUNT_1">%1$s</xliff:g> տպիչ հայտնաբերելու համար</item>
+ <item quantity="other">Տեղադրեք՝ <xliff:g id="COUNT_1">%1$s</xliff:g> տպիչ հայտնաբերելու համար</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Տպվում է՝ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>-ը չեղարկվում է"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Տպիչի սխալ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-in/strings.xml b/packages/PrintSpooler/res/values-in/strings.xml
index 9b72250..4ec0644 100644
--- a/packages/PrintSpooler/res/values-in/strings.xml
+++ b/packages/PrintSpooler/res/values-in/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Layanan yang disarankan"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Layanan dinonaktifkan"</string>
<string name="all_services_title" msgid="5578662754874906455">"Semua layanan"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Pasang untuk menemukan <xliff:g id="COUNT_1">%1$s</xliff:g> printer</item>
+ <item quantity="one">Pasang untuk menemukan <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Mencetak <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Membatalkan <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Ada kesalahan printer <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-is-rIS/strings.xml b/packages/PrintSpooler/res/values-is-rIS/strings.xml
index 37abb5a..e05f07f 100644
--- a/packages/PrintSpooler/res/values-is-rIS/strings.xml
+++ b/packages/PrintSpooler/res/values-is-rIS/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Þjónusta sem mælt er með"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Þjónusta við fatlaða"</string>
<string name="all_services_title" msgid="5578662754874906455">"Öll þjónusta"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Settu upp til að finna <xliff:g id="COUNT_1">%1$s</xliff:g> prentara</item>
+ <item quantity="other">Settu upp til að finna <xliff:g id="COUNT_1">%1$s</xliff:g> prentara</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Prentar <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Hættir við <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Prentaravilla <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-it/strings.xml b/packages/PrintSpooler/res/values-it/strings.xml
index dd4a8cb..39a0a61 100644
--- a/packages/PrintSpooler/res/values-it/strings.xml
+++ b/packages/PrintSpooler/res/values-it/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Servizi consigliati"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Servizi disattivati"</string>
<string name="all_services_title" msgid="5578662754874906455">"Tutti i servizi"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Installa per rilevare <xliff:g id="COUNT_1">%1$s</xliff:g> stampanti</item>
+ <item quantity="one">Installa per rilevare <xliff:g id="COUNT_0">%1$s</xliff:g> stampante</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Stampa di <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Annullamento di <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Errore della stampante: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-iw/strings.xml b/packages/PrintSpooler/res/values-iw/strings.xml
index 1d813bb..9aa4104 100644
--- a/packages/PrintSpooler/res/values-iw/strings.xml
+++ b/packages/PrintSpooler/res/values-iw/strings.xml
@@ -74,6 +74,12 @@
<string name="recommended_services_title" msgid="3799434882937956924">"שירותים מומלצים"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"שירותים מושבתים"</string>
<string name="all_services_title" msgid="5578662754874906455">"כל השירותים"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="two">התקן כדי לגלות <xliff:g id="COUNT_1">%1$s</xliff:g> מדפסות</item>
+ <item quantity="many">התקן כדי לגלות <xliff:g id="COUNT_1">%1$s</xliff:g> מדפסות</item>
+ <item quantity="other">התקן כדי לגלות <xliff:g id="COUNT_1">%1$s</xliff:g> מדפסות</item>
+ <item quantity="one">התקן כדי לגלות מדפסת <xliff:g id="COUNT_0">%1$s</xliff:g></item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"מדפיס את <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"מבטל את <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"שגיאת מדפסת ב-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ja/strings.xml b/packages/PrintSpooler/res/values-ja/strings.xml
index 946052a..f97efc1 100644
--- a/packages/PrintSpooler/res/values-ja/strings.xml
+++ b/packages/PrintSpooler/res/values-ja/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"推奨されているサービス"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"無効になっているサービス"</string>
<string name="all_services_title" msgid="5578662754874906455">"すべてのサービス"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> 台のプリンタを検索するにはインストールします</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> 台のプリンタを検索するにはインストールします</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>を印刷しています"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>をキャンセルしています"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"プリンタエラー: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ka-rGE/strings.xml b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
index 94152b1..9cb8b39 100644
--- a/packages/PrintSpooler/res/values-ka-rGE/strings.xml
+++ b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"რეკომენდებული სერვისები"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"გათიშული სერვისები"</string>
<string name="all_services_title" msgid="5578662754874906455">"ყველა სერვისი"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">დააინსტალირეთ <xliff:g id="COUNT_1">%1$s</xliff:g> პრინტერის აღმოსაჩენად</item>
+ <item quantity="one">დააინსტალირეთ <xliff:g id="COUNT_0">%1$s</xliff:g> პრინტერის აღმოსაჩენად</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"იბეჭდება <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"მიმდინარეობს <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>-ის გაუქმება"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"ბეჭდვის შეცდომა <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
index c647dab..37b2cd3 100644
--- a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
+++ b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Ұсынылған қызметтер"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Өшірілген қызметтер"</string>
<string name="all_services_title" msgid="5578662754874906455">"Барлық қызметтер"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> принтерді табу үшін орнатыңыз</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> принтерді табу үшін орнатыңыз</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> басып шығарылуда"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> жұмысын тоқтатуда"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> принтер қателігі"</string>
diff --git a/packages/PrintSpooler/res/values-km-rKH/strings.xml b/packages/PrintSpooler/res/values-km-rKH/strings.xml
index 330edf5..12d296d 100644
--- a/packages/PrintSpooler/res/values-km-rKH/strings.xml
+++ b/packages/PrintSpooler/res/values-km-rKH/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"សេវាកម្មដែលបានណែនាំ"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"សេវាកម្មដែលបិទដំណើរការ"</string>
<string name="all_services_title" msgid="5578662754874906455">"សេវាកម្មទាំងអស់"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">ដំឡើងដើម្បីរកមើលម៉ាស៊ីនបោះពុម្ព <xliff:g id="COUNT_1">%1$s</xliff:g></item>
+ <item quantity="one">ដំឡើងដើម្បីរកមើលម៉ាស៊ីនបោះពុម្ព <xliff:g id="COUNT_0">%1$s</xliff:g></item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"កំពុងបោះពុម្ព <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"ការបោះបង់ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"កំហុសម៉ាស៊ីនបោះពុម្ព <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-kn-rIN/strings.xml b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
index f1cef86..8b1acdd 100644
--- a/packages/PrintSpooler/res/values-kn-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"ಶಿಫಾರಸು ಮಾಡಲಾದ ಸೇವೆಗಳು"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾದ ಸೇವೆಗಳು"</string>
<string name="all_services_title" msgid="5578662754874906455">"ಎಲ್ಲ ಸೇವೆಗಳು"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> ಪ್ರಿಂಟರ್ಗಳನ್ನು ಶೋಧಿಸಲು ಸ್ಥಾಪಿಸಿ</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ಪ್ರಿಂಟರ್ಗಳನ್ನು ಶೋಧಿಸಲು ಸ್ಥಾಪಿಸಿ</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ಮುದ್ರಿಸಲಾಗುತ್ತಿದೆ"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ರದ್ದು ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"ಮುದ್ರಕ ದೋಷ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ko/strings.xml b/packages/PrintSpooler/res/values-ko/strings.xml
index d3cc967..e6ca240 100644
--- a/packages/PrintSpooler/res/values-ko/strings.xml
+++ b/packages/PrintSpooler/res/values-ko/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"권장 서비스"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"사용 중지된 서비스"</string>
<string name="all_services_title" msgid="5578662754874906455">"모든 서비스"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g>개 프린터를 표시하려면 설치하세요.</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g>개 프린터를 표시하려면 설치하세요.</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> 인쇄 중"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> 취소 중"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"프린터 오류: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ky-rKG/strings.xml b/packages/PrintSpooler/res/values-ky-rKG/strings.xml
index d84e5d8..ae0b05e 100644
--- a/packages/PrintSpooler/res/values-ky-rKG/strings.xml
+++ b/packages/PrintSpooler/res/values-ky-rKG/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Сунушталган кызматтар"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Өчүрүлгөн кызматтар"</string>
<string name="all_services_title" msgid="5578662754874906455">"Бардык кызматтар"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Орнотсоңуз <xliff:g id="COUNT_1">%1$s</xliff:g> принтер таап аласыз</item>
+ <item quantity="one">Орнотсоңуз <xliff:g id="COUNT_0">%1$s</xliff:g> принтер таап аласыз</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> басылууда"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> токтотулууда"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Принтерде ката кетти: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-lo-rLA/strings.xml b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
index 6a69053..2392e4a 100644
--- a/packages/PrintSpooler/res/values-lo-rLA/strings.xml
+++ b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"ບໍລິການທີ່ແນະນຳ"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"ບໍລິການທີ່ຖືກປິດການນຳໃຊ້"</string>
<string name="all_services_title" msgid="5578662754874906455">"ບໍລິການທັງໝົດ"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">ຕິດຕັ້ງເພື່ອຄົ້ນພົບເຄື່ອງພິມ <xliff:g id="COUNT_1">%1$s</xliff:g> ເຄື່ອງ</item>
+ <item quantity="one">ຕິດຕັ້ງເພື່ອຄົ້ນພົບເຄື່ອງພິມ <xliff:g id="COUNT_0">%1$s</xliff:g> ເຄື່ອງ</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"ກຳລັງພິມ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"ກຳລັງຍົກເລີກ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"ເຄື່ອງພິມເກີດຂໍ້ຜິດພາດ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-lt/strings.xml b/packages/PrintSpooler/res/values-lt/strings.xml
index ddcaba7..65ccc2b 100644
--- a/packages/PrintSpooler/res/values-lt/strings.xml
+++ b/packages/PrintSpooler/res/values-lt/strings.xml
@@ -74,6 +74,12 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Rekomenduojamos paslaugos"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Išjungtos paslaugos"</string>
<string name="all_services_title" msgid="5578662754874906455">"Visos paslaugos"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Įdiekite, kad būtų rastas <xliff:g id="COUNT_1">%1$s</xliff:g> spausdintuvas</item>
+ <item quantity="few">Įdiekite, kad būtų rasti <xliff:g id="COUNT_1">%1$s</xliff:g> spausdintuvai</item>
+ <item quantity="many">Įdiekite, kad būtų rasta <xliff:g id="COUNT_1">%1$s</xliff:g> spausdintuvo</item>
+ <item quantity="other">Įdiekite, kad būtų rasta <xliff:g id="COUNT_1">%1$s</xliff:g> spausdintuvų</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Spausdinama: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Atšaukiama: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Spausdintuvo klaida: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-lv/strings.xml b/packages/PrintSpooler/res/values-lv/strings.xml
index 50ba32d..1bcfe78 100644
--- a/packages/PrintSpooler/res/values-lv/strings.xml
+++ b/packages/PrintSpooler/res/values-lv/strings.xml
@@ -73,6 +73,11 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Ieteiktie pakalpojumi"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Atspējotie pakalpojumi"</string>
<string name="all_services_title" msgid="5578662754874906455">"Visi pakalpojumi"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="zero">Instalējiet, lai atklātu <xliff:g id="COUNT_1">%1$s</xliff:g> printerus</item>
+ <item quantity="one">Instalējiet, lai atklātu <xliff:g id="COUNT_1">%1$s</xliff:g> printeri</item>
+ <item quantity="other">Instalējiet, lai atklātu <xliff:g id="COUNT_1">%1$s</xliff:g> printerus</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Notiek darba <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> drukāšana…"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Pārtrauc drukas darbu <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>…"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printera kļūda ar darbu <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-mk-rMK/strings.xml b/packages/PrintSpooler/res/values-mk-rMK/strings.xml
index a189042..d29566bc 100644
--- a/packages/PrintSpooler/res/values-mk-rMK/strings.xml
+++ b/packages/PrintSpooler/res/values-mk-rMK/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Препорачани услуги"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Оневозможени услуги"</string>
<string name="all_services_title" msgid="5578662754874906455">"Сите услуги"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Инсталирајте за да пронајдете <xliff:g id="COUNT_1">%1$s</xliff:g> печатач</item>
+ <item quantity="other">Инсталирајте за да пронајдете <xliff:g id="COUNT_1">%1$s</xliff:g> печатачи</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> се печати"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> се откажува"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Грешка при печатење <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ml-rIN/strings.xml b/packages/PrintSpooler/res/values-ml-rIN/strings.xml
index 5625632..16d654c 100644
--- a/packages/PrintSpooler/res/values-ml-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-ml-rIN/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"ശുപാർശ ചെയ്യപ്പെടുന്ന സേവനങ്ങൾ"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"പ്രവർത്തനരഹിതമാക്കിയ സേവനങ്ങൾ"</string>
<string name="all_services_title" msgid="5578662754874906455">"എല്ലാ സേവനങ്ങളും"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> പ്രിന്ററുകൾ കണ്ടെത്തുന്നതിന് ഇൻസ്റ്റാൾ ചെയ്യുക</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> പ്രിന്റർ കണ്ടെത്തുന്നതിന് ഇൻസ്റ്റാൾ ചെയ്യുക</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> പ്രിന്റുചെയ്യുന്നു"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> റദ്ദാക്കുന്നു"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"പ്രിന്റർ പിശക് <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-mn-rMN/strings.xml b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
index 7797944..ded0665 100644
--- a/packages/PrintSpooler/res/values-mn-rMN/strings.xml
+++ b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Санал болгосон үйлчилгээ"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Идэвхгүй болгосон үйлчилгээ"</string>
<string name="all_services_title" msgid="5578662754874906455">"Бүх үйлчилгээ"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"> <xliff:g id="COUNT_1">%1$s</xliff:g> хэвлэгч олохын тулд суулгах</item>
+ <item quantity="one"> <xliff:g id="COUNT_0">%1$s</xliff:g> хэвлэгч олохын тулд суулгах</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Хэвлэж байна <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Цуцлаж байна <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Принтерийн алдаа <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-mr-rIN/strings.xml b/packages/PrintSpooler/res/values-mr-rIN/strings.xml
index ee09db2..5436635 100644
--- a/packages/PrintSpooler/res/values-mr-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-mr-rIN/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"शिफारस केलेल्या सेवा"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"अक्षम केलल्या सेवा"</string>
<string name="all_services_title" msgid="5578662754874906455">"सर्व सेवा"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर शोधण्यासाठी स्थापित करा</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर शोधण्यासाठी स्थापित करा</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> मुद्रण करीत आहे"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> रद्द करीत आहे"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिंटर त्रुटी <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ms-rMY/strings.xml b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
index 4042c71..8af5232 100644
--- a/packages/PrintSpooler/res/values-ms-rMY/strings.xml
+++ b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Perkhidmatan yang disyorkan"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Perkhidmatan yang dilumpuhkan"</string>
<string name="all_services_title" msgid="5578662754874906455">"Semua perkhidmatan"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Pasang untuk menemui <xliff:g id="COUNT_1">%1$s</xliff:g> pencetak</item>
+ <item quantity="one">Pasang untuk menemui <xliff:g id="COUNT_0">%1$s</xliff:g> pencetak</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Mencetak <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Membatalkan <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Ralat pencetak <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-my-rMM/strings.xml b/packages/PrintSpooler/res/values-my-rMM/strings.xml
index f34ca67..9b5f46a 100644
--- a/packages/PrintSpooler/res/values-my-rMM/strings.xml
+++ b/packages/PrintSpooler/res/values-my-rMM/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"အကြံပြုထားသည့် ဝန်ဆောင်မှုများ"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"ပိတ်ထားသည့် ဝန်ဆောင်မှုများ"</string>
<string name="all_services_title" msgid="5578662754874906455">"ဝန်ဆောင်မှုများ အားလုံး"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">ပုံနှိပ်စက် <xliff:g id="COUNT_1">%1$s</xliff:g> ခုကို ရှာဖွေရန် စနစ်ထည့်သွင်းပါ</item>
+ <item quantity="one">ပုံနှိပ်စက် <xliff:g id="COUNT_0">%1$s</xliff:g> ခုကို ရှာဖွေရန် စနစ်ထည့်သွင်းပါ</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ကို စာထုတ်နေပါသည်"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ကို ပယ်ဖျက်နေပါသည်"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"စာထုတ်စက်မှ အမှား <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-nb/strings.xml b/packages/PrintSpooler/res/values-nb/strings.xml
index 6b74765..82282ba 100644
--- a/packages/PrintSpooler/res/values-nb/strings.xml
+++ b/packages/PrintSpooler/res/values-nb/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Anbefalte tjenester"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Tjenester som er slått av"</string>
<string name="all_services_title" msgid="5578662754874906455">"Alle tjenester"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Installer for å finne <xliff:g id="COUNT_1">%1$s</xliff:g> printere</item>
+ <item quantity="one">Installer for å finne <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Skriver ut <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Avbryter <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Skriverfeil <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ne-rNP/strings.xml b/packages/PrintSpooler/res/values-ne-rNP/strings.xml
index 8e8bf15..4cf2f51 100644
--- a/packages/PrintSpooler/res/values-ne-rNP/strings.xml
+++ b/packages/PrintSpooler/res/values-ne-rNP/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"सिफारिस गरिएका सेवाहरू"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"असक्षम गरिएका सेवाहरू"</string>
<string name="all_services_title" msgid="5578662754874906455">"सबै सेवाहरू"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिन्टरहरू पत्ता लगाउनका लागि स्थापना गर्नुहोस्</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> प्रिन्टर पत्ता लगाउनका लागि स्थापना गर्नुहोस्</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"प्रिन्ट गरिँदै <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"रद्द गरिँदै <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिन्टर त्रुटि <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-nl/strings.xml b/packages/PrintSpooler/res/values-nl/strings.xml
index 3c65d8a..83b9a22 100644
--- a/packages/PrintSpooler/res/values-nl/strings.xml
+++ b/packages/PrintSpooler/res/values-nl/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Aanbevolen services"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Uitgeschakelde services"</string>
<string name="all_services_title" msgid="5578662754874906455">"Alle services"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Installeren om <xliff:g id="COUNT_1">%1$s</xliff:g> printers te vinden</item>
+ <item quantity="one">Installeren om <xliff:g id="COUNT_0">%1$s</xliff:g> printer te vinden</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> afdrukken"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> annuleren"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printerfout <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-pa-rIN/strings.xml b/packages/PrintSpooler/res/values-pa-rIN/strings.xml
index 934123b..5f3366f 100644
--- a/packages/PrintSpooler/res/values-pa-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-pa-rIN/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"ਸਿਫ਼ਾਰਸ਼ ਕੀਤੀਆਂ ਸੇਵਾਵਾਂ"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"ਅਯੋਗ ਬਣਾਈਆਂ ਗਈਆਂ ਸੇਵਾਵਾਂ"</string>
<string name="all_services_title" msgid="5578662754874906455">"ਸਾਰੀਆਂ ਸੇਵਾਵਾਂ"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> ਪ੍ਰਿੰਟਰ ਖੋਜਣ ਲਈ ਸਥਾਪਤ ਕਰੋ</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ਪ੍ਰਿੰਟਰ ਖੋਜਣ ਲਈ ਸਥਾਪਤ ਕਰੋ</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ਨੂੰ ਪ੍ਰਿੰਟ ਕਰ ਰਿਹਾ ਹੈ"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ਨੂੰ ਰੱਦ ਕਰ ਰਿਹਾ ਹੈ"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"ਪ੍ਰਿੰਟਰ ਅਸ਼ੁੱਧੀ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-pl/strings.xml b/packages/PrintSpooler/res/values-pl/strings.xml
index 80b6070..e7fb7b6 100644
--- a/packages/PrintSpooler/res/values-pl/strings.xml
+++ b/packages/PrintSpooler/res/values-pl/strings.xml
@@ -74,6 +74,12 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Polecane usługi"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Wyłączone usługi"</string>
<string name="all_services_title" msgid="5578662754874906455">"Wszystkie usługi"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="few">Zainstaluj, by wykryć <xliff:g id="COUNT_1">%1$s</xliff:g> drukarki</item>
+ <item quantity="many">Zainstaluj, by wykryć <xliff:g id="COUNT_1">%1$s</xliff:g> drukarek</item>
+ <item quantity="other">Zainstaluj, by wykryć <xliff:g id="COUNT_1">%1$s</xliff:g> drukarki</item>
+ <item quantity="one">Zainstaluj, by wykryć <xliff:g id="COUNT_0">%1$s</xliff:g> drukarkę</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Drukowanie: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Anulowanie: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Błąd drukarki: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-pt-rBR/strings.xml b/packages/PrintSpooler/res/values-pt-rBR/strings.xml
index 4bd1161..dd8cdb2 100644
--- a/packages/PrintSpooler/res/values-pt-rBR/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rBR/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Serviços recomendados"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Serviços desativados"</string>
<string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
+ <item quantity="other">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Imprimindo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Erro ao imprimir <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-pt-rPT/strings.xml b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
index 7660c5c..c1fe7bf 100644
--- a/packages/PrintSpooler/res/values-pt-rPT/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Serviços recomendados"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Serviços desativados"</string>
<string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Instale para detetar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
+ <item quantity="one">Instale para detetar <xliff:g id="COUNT_0">%1$s</xliff:g> impressora</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"A imprimir <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"A cancelar <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Erro da impressora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-pt/strings.xml b/packages/PrintSpooler/res/values-pt/strings.xml
index 4bd1161..dd8cdb2 100644
--- a/packages/PrintSpooler/res/values-pt/strings.xml
+++ b/packages/PrintSpooler/res/values-pt/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Serviços recomendados"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Serviços desativados"</string>
<string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
+ <item quantity="other">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Imprimindo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Erro ao imprimir <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ro/strings.xml b/packages/PrintSpooler/res/values-ro/strings.xml
index dd38c31..b326e09 100644
--- a/packages/PrintSpooler/res/values-ro/strings.xml
+++ b/packages/PrintSpooler/res/values-ro/strings.xml
@@ -73,6 +73,11 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Servicii recomandate"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Servicii dezactivate"</string>
<string name="all_services_title" msgid="5578662754874906455">"Toate serviciile"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="few">Instalați pentru a descoperi <xliff:g id="COUNT_1">%1$s</xliff:g> imprimante</item>
+ <item quantity="other">Instalați pentru a descoperi <xliff:g id="COUNT_1">%1$s</xliff:g> de imprimante</item>
+ <item quantity="one">Instalați pentru a descoperi <xliff:g id="COUNT_0">%1$s</xliff:g> imprimantă</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Se printează <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Se anulează <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Eroare de printare: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ru/strings.xml b/packages/PrintSpooler/res/values-ru/strings.xml
index 6c074ed..5acadbc 100644
--- a/packages/PrintSpooler/res/values-ru/strings.xml
+++ b/packages/PrintSpooler/res/values-ru/strings.xml
@@ -74,6 +74,12 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Рекомендуемые службы"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Отключенные службы"</string>
<string name="all_services_title" msgid="5578662754874906455">"Все службы печати"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Установите, чтобы найти <xliff:g id="COUNT_1">%1$s</xliff:g> принтер</item>
+ <item quantity="few">Установите, чтобы найти <xliff:g id="COUNT_1">%1$s</xliff:g> принтера</item>
+ <item quantity="many">Установите, чтобы найти <xliff:g id="COUNT_1">%1$s</xliff:g> принтеров</item>
+ <item quantity="other">Установите, чтобы найти <xliff:g id="COUNT_1">%1$s</xliff:g> принтера</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Печать задания \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\"…"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Отмена задания <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>…"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Ошибка задания \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\""</string>
diff --git a/packages/PrintSpooler/res/values-si-rLK/strings.xml b/packages/PrintSpooler/res/values-si-rLK/strings.xml
index 8278aee..db4c5fd 100644
--- a/packages/PrintSpooler/res/values-si-rLK/strings.xml
+++ b/packages/PrintSpooler/res/values-si-rLK/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"නිර්දේශිත සේවා"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"අබල කළ සේවා"</string>
<string name="all_services_title" msgid="5578662754874906455">"සියලු සේවා"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">මුද්රණ යන්ත්ර <xliff:g id="COUNT_1">%1$s</xliff:g>ක් සොයා ගැනීමට ස්ථාපනය කරන්න</item>
+ <item quantity="other">මුද්රණ යන්ත්ර <xliff:g id="COUNT_1">%1$s</xliff:g>ක් සොයා ගැනීමට ස්ථාපනය කරන්න</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> මුද්රණය වේ"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"අවලංගු කෙරේ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"මුද්රණ දෝෂය <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-sk/strings.xml b/packages/PrintSpooler/res/values-sk/strings.xml
index 610fe99..63ee5e2 100644
--- a/packages/PrintSpooler/res/values-sk/strings.xml
+++ b/packages/PrintSpooler/res/values-sk/strings.xml
@@ -74,6 +74,12 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Odporúčané služby"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Zakázané služby"</string>
<string name="all_services_title" msgid="5578662754874906455">"Všetky služby"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="few">Nainštalujte a objavte <xliff:g id="COUNT_1">%1$s</xliff:g> tlačiarne</item>
+ <item quantity="many">Nainštalujte a objavte <xliff:g id="COUNT_1">%1$s</xliff:g> tlačiarne</item>
+ <item quantity="other">Nainštalujte a objavte <xliff:g id="COUNT_1">%1$s</xliff:g> tlačiarní</item>
+ <item quantity="one">Nainštalujte a objavte <xliff:g id="COUNT_0">%1$s</xliff:g> tlačiareň</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Prebieha tlač úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Prebieha zrušenie úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Chyba tlačiarne – úloha <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-sl/strings.xml b/packages/PrintSpooler/res/values-sl/strings.xml
index b5124b4..f7616db 100644
--- a/packages/PrintSpooler/res/values-sl/strings.xml
+++ b/packages/PrintSpooler/res/values-sl/strings.xml
@@ -74,6 +74,12 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Priporočene storitve"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Onemogočene storitve"</string>
<string name="all_services_title" msgid="5578662754874906455">"Vse storitve"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Namestite za odkrivanje <xliff:g id="COUNT_1">%1$s</xliff:g> tiskalnika</item>
+ <item quantity="two">Namestite za odkrivanje <xliff:g id="COUNT_1">%1$s</xliff:g> tiskalnikov</item>
+ <item quantity="few">Namestite za odkrivanje <xliff:g id="COUNT_1">%1$s</xliff:g> tiskalnikov</item>
+ <item quantity="other">Namestite za odkrivanje <xliff:g id="COUNT_1">%1$s</xliff:g> tiskalnikov</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Tiskanje: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Preklic: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Napaka tiskalnika: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-sq-rAL/strings.xml b/packages/PrintSpooler/res/values-sq-rAL/strings.xml
index 27bbbf9..f4d2817 100644
--- a/packages/PrintSpooler/res/values-sq-rAL/strings.xml
+++ b/packages/PrintSpooler/res/values-sq-rAL/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Shërbimet e rekomanduara"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Shërbimet e çaktivizuara"</string>
<string name="all_services_title" msgid="5578662754874906455">"Të gjitha shërbimet"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Instaloje për të zbuluar <xliff:g id="COUNT_1">%1$s</xliff:g> printera</item>
+ <item quantity="one">Instaloje për të zbuluar <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Po printon <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Po anulon <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printeri ndeshi në gabim gjatë punës: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-sr/strings.xml b/packages/PrintSpooler/res/values-sr/strings.xml
index ea6fcb7..b285044 100644
--- a/packages/PrintSpooler/res/values-sr/strings.xml
+++ b/packages/PrintSpooler/res/values-sr/strings.xml
@@ -73,6 +73,11 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Препоручене услуге"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Онемогућене услуге"</string>
<string name="all_services_title" msgid="5578662754874906455">"Све услуге"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Инсталирајте да бисте открили <xliff:g id="COUNT_1">%1$s</xliff:g> штампач</item>
+ <item quantity="few">Инсталирајте да бисте открили <xliff:g id="COUNT_1">%1$s</xliff:g> штампача</item>
+ <item quantity="other">Инсталирајте да бисте открили <xliff:g id="COUNT_1">%1$s</xliff:g> штампача</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Штампа се <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Отказује се <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Грешка штампача <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-sv/strings.xml b/packages/PrintSpooler/res/values-sv/strings.xml
index c909e19..4a72800 100644
--- a/packages/PrintSpooler/res/values-sv/strings.xml
+++ b/packages/PrintSpooler/res/values-sv/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Rekommenderade tjänster"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Inaktiverade tjänster"</string>
<string name="all_services_title" msgid="5578662754874906455">"Alla tjänster"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Installera och hitta <xliff:g id="COUNT_1">%1$s</xliff:g> skrivare</item>
+ <item quantity="one">Installera och hitta <xliff:g id="COUNT_0">%1$s</xliff:g> skrivare</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Skriver ut <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Avbryter <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Skrivarfel för <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-sw/strings.xml b/packages/PrintSpooler/res/values-sw/strings.xml
index bd14117..34b935d 100644
--- a/packages/PrintSpooler/res/values-sw/strings.xml
+++ b/packages/PrintSpooler/res/values-sw/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Huduma zinazopendekezwa"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Huduma ambazo haziruhusiwi"</string>
<string name="all_services_title" msgid="5578662754874906455">"Huduma zote"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Sakinisha ili ugundue printa <xliff:g id="COUNT_1">%1$s</xliff:g></item>
+ <item quantity="one">Sakinisha ili ugundue printa <xliff:g id="COUNT_0">%1$s</xliff:g></item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Inachapisha <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Inaghairi <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Hitilafu ya kuchapisha <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ta-rIN/strings.xml b/packages/PrintSpooler/res/values-ta-rIN/strings.xml
index 782ebf2..22f41bf 100644
--- a/packages/PrintSpooler/res/values-ta-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-ta-rIN/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"பரிந்துரைக்கப்படும் அச்சுப் பொறிகள்"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"முடக்கப்பட்ட அச்சுப் பொறிகள்"</string>
<string name="all_services_title" msgid="5578662754874906455">"எல்லா அச்சுப் பொறிகளும்"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> பிரிண்டர்களைக் கண்டறிய, நிறுவவும்</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> பிரிண்டரைக் கண்டறிய, நிறுவவும்</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ஐ அச்சிடுகிறது"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ஐ ரத்துசெய்கிறது"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"பிரிண்டர் பிழை <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-te-rIN/strings.xml b/packages/PrintSpooler/res/values-te-rIN/strings.xml
index ca393c839..1211cfd 100644
--- a/packages/PrintSpooler/res/values-te-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-te-rIN/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"సిఫార్సు చేయబడిన సేవలు"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"నిలిపివేసిన సేవలు"</string>
<string name="all_services_title" msgid="5578662754874906455">"అన్ని సేవలు"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ప్రింటర్లను కనుగొనడానికి ఇన్స్టాల్ చేయండి</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> ప్రింటర్ను కనుగొనడానికి ఇన్స్టాల్ చేయండి</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ను ముద్రిస్తోంది"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ను రద్దు చేస్తోంది"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"ప్రింటర్ లోపం <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-th/strings.xml b/packages/PrintSpooler/res/values-th/strings.xml
index 92b960e..7f99288 100644
--- a/packages/PrintSpooler/res/values-th/strings.xml
+++ b/packages/PrintSpooler/res/values-th/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"บริการที่แนะนำ"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"บริการที่ปิดใช้"</string>
<string name="all_services_title" msgid="5578662754874906455">"บริการทั้งหมด"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">ติดตั้งเพื่อค้นหาเครื่องพิมพ์ <xliff:g id="COUNT_1">%1$s</xliff:g> เครื่อง</item>
+ <item quantity="one">ติดตั้งเพื่อค้นหาเครื่องพิมพ์ <xliff:g id="COUNT_0">%1$s</xliff:g> เครื่อง</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"กำลังพิมพ์ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"กำลังยกเลิก <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"ข้อผิดพลาดเครื่องพิมพ์ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-tl/strings.xml b/packages/PrintSpooler/res/values-tl/strings.xml
index 5a73659..7b50815 100644
--- a/packages/PrintSpooler/res/values-tl/strings.xml
+++ b/packages/PrintSpooler/res/values-tl/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Mga inirerekomendang serbisyo"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Mga naka-disable na serbisyo"</string>
<string name="all_services_title" msgid="5578662754874906455">"Lahat ng serbisyo"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">I-install upang tumuklas ng <xliff:g id="COUNT_1">%1$s</xliff:g> printer</item>
+ <item quantity="other">I-install upang tumuklas ng <xliff:g id="COUNT_1">%1$s</xliff:g> na printer</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Pini-print ang <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Kinakansela ang <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Error sa printer <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-tr/strings.xml b/packages/PrintSpooler/res/values-tr/strings.xml
index f17bc9d..1ca722b 100644
--- a/packages/PrintSpooler/res/values-tr/strings.xml
+++ b/packages/PrintSpooler/res/values-tr/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Önerilen hizmetler"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Devre dışı bırakılmış hizmetler"</string>
<string name="all_services_title" msgid="5578662754874906455">"Tüm hizmetler"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> yazıcıyı keşfetmek için yükleyin</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> yazıcıyı keşfetmek için yükleyin</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> yazdırılıyor"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> iptal ediliyor"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Yazıcı hatası: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-uk/strings.xml b/packages/PrintSpooler/res/values-uk/strings.xml
index 9629ad3..8004639 100644
--- a/packages/PrintSpooler/res/values-uk/strings.xml
+++ b/packages/PrintSpooler/res/values-uk/strings.xml
@@ -74,6 +74,12 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Рекомендовані служби"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Вимкнені служби"</string>
<string name="all_services_title" msgid="5578662754874906455">"Усі служби"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Установіть, щоб знайти <xliff:g id="COUNT_1">%1$s</xliff:g> принтер</item>
+ <item quantity="few">Установіть, щоб знайти <xliff:g id="COUNT_1">%1$s</xliff:g> принтери</item>
+ <item quantity="many">Установіть, щоб знайти <xliff:g id="COUNT_1">%1$s</xliff:g> принтерів</item>
+ <item quantity="other">Установіть, щоб знайти <xliff:g id="COUNT_1">%1$s</xliff:g> принтера</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Завдання \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" друкується"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Завдання \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" скасовується"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Помилка завдання \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\""</string>
diff --git a/packages/PrintSpooler/res/values-ur-rPK/strings.xml b/packages/PrintSpooler/res/values-ur-rPK/strings.xml
index 0d01ee2..19e759cb 100644
--- a/packages/PrintSpooler/res/values-ur-rPK/strings.xml
+++ b/packages/PrintSpooler/res/values-ur-rPK/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"تجویز کردہ سروسز"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"غیر فعال کردہ سروسز"</string>
<string name="all_services_title" msgid="5578662754874906455">"تمام سروسز"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> پرنٹرز دریافت کرنے کیلئے انسٹال کریں</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> پرنٹر دریافت کرنے کیلئے انسٹال کریں</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> پرنٹ کررہا ہے"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> کو منسوخ کر رہا ہے"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"پرنٹر کی خرابی <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
index 1f379d9..cf87a74 100644
--- a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
+++ b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Tavsiya etilgan xizmatlar"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"O‘chirib qo‘yilgan xizmatlar"</string>
<string name="all_services_title" msgid="5578662754874906455">"Barcha xizmatlar"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ta printerni topish uchun o‘rnating</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> ta printerni topish uchun o‘rnating</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Chop etilmoqda: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> bekor qilinmoqda"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printerda xatolik: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-vi/strings.xml b/packages/PrintSpooler/res/values-vi/strings.xml
index b931557..2c1fa27 100644
--- a/packages/PrintSpooler/res/values-vi/strings.xml
+++ b/packages/PrintSpooler/res/values-vi/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Dịch vụ được đề xuất"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Dịch vụ đã tắt"</string>
<string name="all_services_title" msgid="5578662754874906455">"Tất cả dịch vụ"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Cài đặt để phát hiện <xliff:g id="COUNT_1">%1$s</xliff:g> máy in</item>
+ <item quantity="one">Cài đặt để phát hiện <xliff:g id="COUNT_0">%1$s</xliff:g> máy in</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"In <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Hủy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Lỗi máy in <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-zh-rCN/strings.xml b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
index ffc9f85..b350051 100644
--- a/packages/PrintSpooler/res/values-zh-rCN/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"推荐的服务"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"已停用的服务"</string>
<string name="all_services_title" msgid="5578662754874906455">"所有服务"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">安装即可找到 <xliff:g id="COUNT_1">%1$s</xliff:g> 台打印机</item>
+ <item quantity="one">安装即可找到 <xliff:g id="COUNT_0">%1$s</xliff:g> 台打印机</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"正在打印“<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>”"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"正在取消打印“<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>”"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"打印机在打印“<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>”时出错"</string>
diff --git a/packages/PrintSpooler/res/values-zh-rHK/strings.xml b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
index 4411a23..192b41b 100644
--- a/packages/PrintSpooler/res/values-zh-rHK/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"推薦服務"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"已停用的服務"</string>
<string name="all_services_title" msgid="5578662754874906455">"所有服務"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">安裝即可使用 <xliff:g id="COUNT_1">%1$s</xliff:g> 部印表機</item>
+ <item quantity="one">安裝即可使用 <xliff:g id="COUNT_0">%1$s</xliff:g> 部印表機</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"正在列印 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"正在取消 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"打印機錯誤:<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-zh-rTW/strings.xml b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
index 98126a7..4aa5681 100644
--- a/packages/PrintSpooler/res/values-zh-rTW/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"建議的列印服務"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"已停用的列印服務"</string>
<string name="all_services_title" msgid="5578662754874906455">"所有列印服務"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">安裝即可使用 <xliff:g id="COUNT_1">%1$s</xliff:g> 個印表機</item>
+ <item quantity="one">安裝即可使用 <xliff:g id="COUNT_0">%1$s</xliff:g> 個印表機</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"正在列印 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"正在取消 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"印表機發生錯誤:<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-zu/strings.xml b/packages/PrintSpooler/res/values-zu/strings.xml
index f2b4990..121022b 100644
--- a/packages/PrintSpooler/res/values-zu/strings.xml
+++ b/packages/PrintSpooler/res/values-zu/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Amasevisi anconyiwe"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Amasevisi akhutshaziwe"</string>
<string name="all_services_title" msgid="5578662754874906455">"Onke amasevisi"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Faka ukuze uthole amaphrinta we-<xliff:g id="COUNT_1">%1$s</xliff:g></item>
+ <item quantity="other">Faka ukuze uthole amaphrinta we-<xliff:g id="COUNT_1">%1$s</xliff:g></item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Iphrinta i-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Ikhansela i-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Iphutha lephrinta ye-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
index af4c347..0feda92 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
@@ -244,9 +244,20 @@
ranges = PageRangeUtils.normalize(ranges);
+ int lastPageIdx = mEditor.getPageCount() - 1;
+
final int rangeCount = ranges.length;
for (int i = rangeCount - 1; i >= 0; i--) {
PageRange range = ranges[i];
+
+ // Ignore removal of pages that are outside the document
+ if (range.getEnd() > lastPageIdx) {
+ if (range.getStart() > lastPageIdx) {
+ continue;
+ }
+ range = new PageRange(range.getStart(), lastPageIdx);
+ }
+
for (int j = range.getEnd(); j >= range.getStart(); j--) {
mEditor.removePage(j);
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index dba6a8b..cde0fa3 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -476,7 +476,7 @@
}
private void onPrintDocumentError(String message) {
- mProgressMessageController.cancel();
+ setState(mProgressMessageController.cancel());
ensureErrorUiShown(null, PrintErrorFragment.ACTION_RETRY);
setState(STATE_UPDATE_FAILED);
@@ -502,7 +502,7 @@
Log.i(LOG_TAG, "onUpdateCanceled()");
}
- mProgressMessageController.cancel();
+ setState(mProgressMessageController.cancel());
ensurePreviewUiShown();
switch (mState) {
@@ -524,7 +524,7 @@
Log.i(LOG_TAG, "onUpdateCompleted()");
}
- mProgressMessageController.cancel();
+ setState(mProgressMessageController.cancel());
ensurePreviewUiShown();
// Update the print job with the info for the written document. The page
@@ -572,7 +572,7 @@
Log.i(LOG_TAG, "onUpdateFailed()");
}
- mProgressMessageController.cancel();
+ setState(mProgressMessageController.cancel());
ensureErrorUiShown(error, PrintErrorFragment.ACTION_RETRY);
if (mState == STATE_CREATE_FILE_FAILED
@@ -1169,6 +1169,18 @@
doFinish();
}
+ /**
+ * Update the selected pages from the text field.
+ */
+ private void updateSelectedPagesFromTextField() {
+ PageRange[] selectedPages = computeSelectedPages();
+ if (!Arrays.equals(mSelectedPages, selectedPages)) {
+ mSelectedPages = selectedPages;
+ // Update preview.
+ updatePrintPreviewController(false);
+ }
+ }
+
private void confirmPrint() {
setState(STATE_PRINT_CONFIRMED);
@@ -1178,14 +1190,10 @@
addCurrentPrinterToHistory();
setUserPrinted();
- PageRange[] selectedPages = computeSelectedPages();
- if (!Arrays.equals(mSelectedPages, selectedPages)) {
- mSelectedPages = selectedPages;
- // Update preview.
- updatePrintPreviewController(false);
- }
-
+ // updateSelectedPagesFromTextField migth update the preview, hence apply the preview first
updateSelectedPagesFromPreview();
+ updateSelectedPagesFromTextField();
+
mPrintPreviewController.closeOptions();
if (canUpdateDocument()) {
@@ -1485,6 +1493,10 @@
cancelPrint();
}
} else if (view == mMoreOptionsButton) {
+ // The selected pages is only applied once the user leaves the text field. A click
+ // on this button, does not count as leaving.
+ updateSelectedPagesFromTextField();
+
if (mCurrentPrinter != null) {
startAdvancedPrintOptionsActivity(mCurrentPrinter);
}
@@ -2066,8 +2078,9 @@
mSpoolerProvider.destroy();
}
+ setState(mProgressMessageController.cancel());
+
if (mState != STATE_INITIALIZING) {
- mProgressMessageController.cancel();
mPrintedDocument.finish();
mPrintedDocument.destroy();
mPrintPreviewController.destroy(new Runnable() {
@@ -2773,13 +2786,7 @@
}
if (view == mPageRangeEditText && !hasFocus) {
- PageRange[] selectedPages = computeSelectedPages();
- if (selectedPages != null && !Arrays.equals(mSelectedPages, selectedPages)) {
- mSelectedPages = selectedPages;
-
- // Update preview.
- updatePrintPreviewController(false);
- }
+ updateSelectedPagesFromTextField();
}
}
}
@@ -2910,29 +2917,50 @@
private boolean mPosted;
+ /** State before run was executed */
+ private int mPreviousState = -1;
+
public ProgressMessageController(Context context) {
mHandler = new Handler(context.getMainLooper(), null, false);
}
public void post() {
- if (mPosted) {
+ if (mState == STATE_UPDATE_SLOW) {
+ setState(STATE_UPDATE_SLOW);
+ ensureProgressUiShown();
+ updateOptionsUi();
+
+ return;
+ } else if (mPosted) {
return;
}
+ mPreviousState = -1;
mPosted = true;
mHandler.postDelayed(this, PROGRESS_TIMEOUT_MILLIS);
}
- public void cancel() {
+ private int getStateAfterCancel() {
+ if (mPreviousState == -1) {
+ return mState;
+ } else {
+ return mPreviousState;
+ }
+ }
+
+ public int cancel() {
if (!mPosted) {
- return;
+ return getStateAfterCancel();
}
mPosted = false;
mHandler.removeCallbacks(this);
+
+ return getStateAfterCancel();
}
@Override
public void run() {
mPosted = false;
+ mPreviousState = mState;
setState(STATE_UPDATE_SLOW);
ensureProgressUiShown();
updateOptionsUi();
@@ -3081,12 +3109,10 @@
List<PageRange> rangesToShred = new ArrayList<>();
PageRange previousRange = null;
- final int pageCount = printJob.getDocumentInfo().getPageCount();
-
PageRange[] printedPages = printJob.getPages();
final int rangeCount = printedPages.length;
for (int i = 0; i < rangeCount; i++) {
- PageRange range = PageRangeUtils.asAbsoluteRange(printedPages[i], pageCount);
+ PageRange range = printedPages[i];
if (previousRange == null) {
final int startPageIdx = 0;
@@ -3105,11 +3131,8 @@
}
if (i == rangeCount - 1) {
- final int startPageIdx = range.getEnd() + 1;
- final int endPageIdx = printJob.getDocumentInfo().getPageCount() - 1;
- if (startPageIdx <= endPageIdx) {
- PageRange removedRange = new PageRange(startPageIdx, endPageIdx);
- rangesToShred.add(removedRange);
+ if (range.getEnd() != Integer.MAX_VALUE) {
+ rangesToShred.add(new PageRange(range.getEnd() + 1, Integer.MAX_VALUE));
}
}
diff --git a/packages/SettingsLib/res/values-be-rBY/strings.xml b/packages/SettingsLib/res/values-be-rBY/strings.xml
index ebb5a59..a70fc69 100644
--- a/packages/SettingsLib/res/values-be-rBY/strings.xml
+++ b/packages/SettingsLib/res/values-be-rBY/strings.xml
@@ -278,7 +278,7 @@
<string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Запусціць апрацоўшчыкі WebView у ізаляваным працэсе."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Рэалізацыя WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Наладзіць рэалізацыю WebView"</string>
- <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Гэты элемент больш не даступны для выбару. Паспрабуйце яшчэ раз."</string>
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Гэты варыянт больш не даступны. Паспрабуйце яшчэ раз."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Перайсці на шыфраванне файлаў"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Пераход..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Шыфраванне файлаў ужо дзейнічае"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index fe3ef1a..a560e3c 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -733,25 +733,44 @@
<!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery charging/discharging -->
<string name="power_remaining_duration_only">Approx. <xliff:g id="time">%1$s</xliff:g> left</string>
+ <!-- [CHAR_LIMIT=40] Short label for estimated remaining duration of battery charging/discharging -->
+ <string name="power_remaining_duration_only_short"><xliff:g id="time">%1$s</xliff:g> left</string>
+
<!-- [CHAR_LIMIT=40] Label for battery level chart when discharging with duration -->
<string name="power_discharging_duration"><xliff:g id="level">%1$s</xliff:g>
- approx. <xliff:g id="time">%2$s</xliff:g> left</string>
+ <!-- [CHAR_LIMIT=40] Label for battery level chart when discharging with duration -->
+ <string name="power_discharging_duration_short"><xliff:g id="level">%1$s</xliff:g>
+ - <xliff:g id="time">%2$s</xliff:g> left</string>
+
<!-- [CHAR_LIMIT=40] Label for battery level chart when charging -->
<string name="power_charging"><xliff:g id="level">%1$s</xliff:g> -
<xliff:g id="state">%2$s</xliff:g></string>
<!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
<string name="power_charging_duration"><xliff:g id="level">%1$s</xliff:g> -
<xliff:g id="time">%2$s</xliff:g> until full</string>
+ <!-- [CHAR_LIMIT=40] Short label for battery level chart when charging with duration -->
+ <string name="power_charging_duration_short"><xliff:g id="level">%1$s</xliff:g> -
+ <xliff:g id="time">%2$s</xliff:g></string>
<!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
<string name="power_charging_duration_ac"><xliff:g id="level">%1$s</xliff:g> -
<xliff:g id="time">%2$s</xliff:g> until full on AC</string>
+ <!-- [CHAR_LIMIT=40] Short label for battery level chart when charging with duration -->
+ <string name="power_charging_duration_ac_short"><xliff:g id="level">%1$s</xliff:g> -
+ <xliff:g id="time">%2$s</xliff:g></string>
<!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
<string name="power_charging_duration_usb"><xliff:g id="level">%1$s</xliff:g> -
<xliff:g id="time">%2$s</xliff:g> until full over USB</string>
+ <!-- [CHAR_LIMIT=40] Short label for battery level chart when charging with duration -->
+ <string name="power_charging_duration_usb_short"><xliff:g id="level">%1$s</xliff:g> -
+ <xliff:g id="time">%2$s</xliff:g></string>
<!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
<string name="power_charging_duration_wireless"><xliff:g id="level">%1$s</xliff:g> -
<xliff:g id="time">%2$s</xliff:g> until full from wireless</string>
+ <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
+ <string name="power_charging_duration_wireless_short"><xliff:g id="level">%1$s</xliff:g> -
+ <xliff:g id="time">%2$s</xliff:g></string>
<!-- Battery Info screen. Value for a status item. Used for diagnostic info screens, precise translation isn't needed -->
<string name="battery_info_status_unknown">Unknown</string>
@@ -759,10 +778,16 @@
<string name="battery_info_status_charging">Charging</string>
<!-- [CHAR_LIMIT=20] Battery use screen. Battery status shown in chart label when charging on AC. -->
<string name="battery_info_status_charging_ac">Charging on AC</string>
+ <!-- [CHAR_LIMIT=20] Battery short status label when charing on AC -->
+ <string name="battery_info_status_charging_ac_short">Charging</string>
<!-- [CHAR_LIMIT=20] Battery use screen. Battery status shown in chart label when charging over USB. -->
<string name="battery_info_status_charging_usb">Charging over USB</string>
+ <!-- [CHAR_LIMIT=20] Battery short status label when charging over USB. -->
+ <string name="battery_info_status_charging_usb_short">Charging</string>
<!-- [CHAR_LIMIT=20] Battery use screen. Battery status shown in chart label when charging over a wireless connection. -->
<string name="battery_info_status_charging_wireless">Charging wirelessly</string>
+ <!-- [CHAR_LIMIT=20] Battery short status label when charging wirelessly. -->
+ <string name="battery_info_status_charging_wireless_short">Charging</string>
<!-- Battery Info screen. Value for a status item. Used for diagnostic info screens, precise translation isn't needed -->
<string name="battery_info_status_discharging">Not charging</string>
<!-- Battery Info screen. Value for a status item. Used for diagnostic info screens, precise translation isn't needed -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java b/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java
index 6b29e21..fa1f91f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java
+++ b/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java
@@ -25,6 +25,7 @@
import android.os.Bundle;
import android.os.SystemClock;
import android.text.format.Formatter;
+import android.util.Log;
import android.util.SparseIntArray;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settingslib.graph.UsageView;
@@ -95,6 +96,11 @@
}
public static void getBatteryInfo(final Context context, final Callback callback) {
+ BatteryInfo.getBatteryInfo(context, callback, false);
+ }
+
+ public static void getBatteryInfo(final Context context, final Callback callback,
+ boolean shortString) {
new AsyncTask<Void, Void, BatteryStats>() {
@Override
protected BatteryStats doInBackground(Void... params) {
@@ -109,14 +115,20 @@
Intent batteryBroadcast = context.registerReceiver(null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
BatteryInfo batteryInfo = BatteryInfo.getBatteryInfo(context,
- batteryBroadcast, batteryStats, elapsedRealtimeUs);
+ batteryBroadcast, batteryStats, elapsedRealtimeUs, shortString);
callback.onBatteryInfoLoaded(batteryInfo);
}
}.execute();
}
public static BatteryInfo getBatteryInfo(Context context, Intent batteryBroadcast,
- BatteryStats stats, long elapsedRealtimeUs) {
+ BatteryStats stats, long elapsedRealtimeUs) {
+ return BatteryInfo.getBatteryInfo(context, batteryBroadcast, stats, elapsedRealtimeUs,
+ false);
+ }
+
+ public static BatteryInfo getBatteryInfo(Context context, Intent batteryBroadcast,
+ BatteryStats stats, long elapsedRealtimeUs, boolean shortString) {
BatteryInfo info = new BatteryInfo();
info.mStats = stats;
info.mBatteryLevel = Utils.getBatteryLevel(batteryBroadcast);
@@ -129,9 +141,13 @@
info.remainingTimeUs = drainTime;
String timeString = Formatter.formatShortElapsedTime(context,
drainTime / 1000);
- info.remainingLabel = resources.getString(R.string.power_remaining_duration_only,
+ info.remainingLabel = resources.getString(
+ shortString ? R.string.power_remaining_duration_only_short
+ : R.string.power_remaining_duration_only,
timeString);
- info.mChargeLabelString = resources.getString(R.string.power_discharging_duration,
+ info.mChargeLabelString = resources.getString(
+ shortString ? R.string.power_discharging_duration_short
+ : R.string.power_discharging_duration,
info.batteryPercentString, timeString);
} else {
info.remainingLabel = null;
@@ -140,7 +156,7 @@
} else {
final long chargeTime = stats.computeChargeTimeRemaining(elapsedRealtimeUs);
final String statusLabel = Utils.getBatteryStatus(
- resources, batteryBroadcast);
+ resources, batteryBroadcast, shortString);
final int status = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_STATUS,
BatteryManager.BATTERY_STATUS_UNKNOWN);
if (chargeTime > 0 && status != BatteryManager.BATTERY_STATUS_FULL) {
@@ -151,13 +167,17 @@
int plugType = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
int resId;
if (plugType == BatteryManager.BATTERY_PLUGGED_AC) {
- resId = R.string.power_charging_duration_ac;
+ resId = shortString ? R.string.power_charging_duration_ac_short
+ : R.string.power_charging_duration_ac;
} else if (plugType == BatteryManager.BATTERY_PLUGGED_USB) {
- resId = R.string.power_charging_duration_usb;
+ resId = shortString ? R.string.power_charging_duration_usb_short
+ : R.string.power_charging_duration_usb;
} else if (plugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
- resId = R.string.power_charging_duration_wireless;
+ resId = shortString ? R.string.power_charging_duration_wireless_short
+ : R.string.power_charging_duration_wireless;
} else {
- resId = R.string.power_charging_duration;
+ resId = shortString ? R.string.power_charging_duration_short
+ : R.string.power_charging_duration;
}
info.remainingLabel = resources.getString(R.string.power_remaining_duration_only,
timeString);
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 74c1ebd..586f269 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -112,20 +112,26 @@
}
public static String getBatteryStatus(Resources res, Intent batteryChangedIntent) {
- final Intent intent = batteryChangedIntent;
+ return Utils.getBatteryStatus(res, batteryChangedIntent, false);
+ }
- int plugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
- int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
+ public static String getBatteryStatus(Resources res, Intent batteryChangedIntent,
+ boolean shortString) {
+ int plugType = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
+ int status = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_STATUS,
BatteryManager.BATTERY_STATUS_UNKNOWN);
String statusString;
if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
int resId;
if (plugType == BatteryManager.BATTERY_PLUGGED_AC) {
- resId = R.string.battery_info_status_charging_ac;
+ resId = shortString ? R.string.battery_info_status_charging_ac_short
+ : R.string.battery_info_status_charging_ac;
} else if (plugType == BatteryManager.BATTERY_PLUGGED_USB) {
- resId = R.string.battery_info_status_charging_usb;
+ resId = shortString ? R.string.battery_info_status_charging_usb_short
+ : R.string.battery_info_status_charging_usb;
} else if (plugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
- resId = R.string.battery_info_status_charging_wireless;
+ resId = shortString ? R.string.battery_info_status_charging_wireless_short
+ : R.string.battery_info_status_charging_wireless;
} else {
resId = R.string.battery_info_status_charging;
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 987b5ea..61c9f2b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -21,6 +21,7 @@
import android.app.AppGlobals;
import android.app.backup.BackupManager;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
@@ -63,6 +64,7 @@
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.providers.settings.SettingsState.Setting;
+import com.android.server.SystemConfig;
import java.io.File;
import java.io.FileDescriptor;
@@ -1940,7 +1942,7 @@
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 125;
+ private static final int SETTINGS_VERSION = 126;
private final int mUserId;
@@ -2136,6 +2138,35 @@
currentVersion = 125;
}
+ if (currentVersion == 125) {
+ // Version 125: Allow OEMs to set the default VR service.
+ final SettingsState secureSettings = getSecureSettingsLocked(userId);
+
+ Setting currentSetting = secureSettings.getSettingLocked(
+ Settings.Secure.ENABLED_VR_LISTENERS);
+ if (currentSetting == null) {
+ ArraySet<ComponentName> l =
+ SystemConfig.getInstance().getDefaultVrComponents();
+
+ if (l != null && !l.isEmpty()) {
+ StringBuilder b = new StringBuilder();
+ boolean start = true;
+ for (ComponentName c : l) {
+ if (!start) {
+ b.append(':');
+ }
+ b.append(c.flattenToString());
+ start = false;
+ }
+ secureSettings.insertSettingLocked(
+ Settings.Secure.ENABLED_VR_LISTENERS, b.toString(),
+ SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+
+ }
+ currentVersion = 126;
+ }
+
// vXXX: Add new settings above this point.
// Return the current version.
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 0c35573..b557dc4 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -139,7 +139,7 @@
<activity
android:name=".BugreportWarningActivity"
- android:theme="@*android:style/Theme.Material.DayNight.Dialog.Alert"
+ android:theme="@android:style/Theme.Material.Light.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true"
android:exported="false" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_fade_in.xml b/packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_gain_animation.xml
similarity index 78%
rename from packages/SystemUI/res/anim/tv_pip_controls_fade_in.xml
rename to packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_gain_animation.xml
index 89e4aac..ebc6a4a7 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_fade_in.xml
+++ b/packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_gain_animation.xml
@@ -17,13 +17,13 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
- android:propertyName="translationY"
- android:valueTo="10dp"
- android:interpolator="@android:interpolator/linear_out_slow_in"
+ android:propertyName="scaleX"
+ android:valueTo="1.0"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
android:duration="@integer/recents_tv_pip_focus_anim_duration" />
<objectAnimator
- android:propertyName="alpha"
+ android:propertyName="scaleY"
android:valueTo="1.0"
- android:interpolator="@android:interpolator/linear_out_slow_in"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
android:duration="@integer/recents_tv_pip_focus_anim_duration" />
</set>
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_fade_in.xml b/packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_lose_animation.xml
similarity index 76%
copy from packages/SystemUI/res/anim/tv_pip_controls_fade_in.xml
copy to packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_lose_animation.xml
index 89e4aac..95499bd 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_fade_in.xml
+++ b/packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_lose_animation.xml
@@ -17,13 +17,13 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
- android:propertyName="translationY"
- android:valueTo="10dp"
- android:interpolator="@android:interpolator/linear_out_slow_in"
+ android:propertyName="scaleX"
+ android:valueTo="0.7"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
android:duration="@integer/recents_tv_pip_focus_anim_duration" />
<objectAnimator
- android:propertyName="alpha"
- android:valueTo="1.0"
- android:interpolator="@android:interpolator/linear_out_slow_in"
+ android:propertyName="scaleY"
+ android:valueTo="0.7"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
android:duration="@integer/recents_tv_pip_focus_anim_duration" />
</set>
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_fade_out.xml b/packages/SystemUI/res/anim/tv_pip_controls_fade_out.xml
deleted file mode 100644
index c73fed6..0000000
--- a/packages/SystemUI/res/anim/tv_pip_controls_fade_out.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android">
-
- <objectAnimator
- android:propertyName="translationY"
- android:valueTo="0dp"
- android:interpolator="@android:interpolator/fast_out_linear_in"
- android:duration="@integer/recents_tv_pip_focus_anim_duration" />
- <objectAnimator
- android:propertyName="alpha"
- android:valueTo="0.0"
- android:interpolator="@android:interpolator/fast_out_linear_in"
- android:duration="@integer/recents_tv_pip_focus_anim_duration" />
-</set>
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_gain_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_gain_animation.xml
new file mode 100644
index 0000000..7555bdd
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_gain_animation.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:propertyName="translationY"
+ android:valueTo="0dp"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="@integer/recents_tv_pip_focus_anim_duration" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_lose_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_lose_animation.xml
new file mode 100644
index 0000000..b40ccd4
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_lose_animation.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:propertyName="translationY"
+ android:valueTo="-57dp"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="@integer/recents_tv_pip_focus_anim_duration" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
new file mode 100644
index 0000000..681ff91
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:propertyName="alpha"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="@integer/recents_tv_pip_focus_anim_duration" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml
new file mode 100644
index 0000000..e6deb0f
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:propertyName="alpha"
+ android:valueTo="0"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="@integer/recents_tv_pip_focus_anim_duration" />
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_image.png
deleted file mode 100644
index 7b0fcc7..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_notify_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_image_error.png
deleted file mode 100644
index 73e9c96..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_notify_image_error.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-mdpi/stat_notify_image.png
deleted file mode 100644
index a02e21c..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_notify_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-mdpi/stat_notify_image_error.png
deleted file mode 100644
index 4af2617..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_notify_image_error.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-xhdpi/stat_notify_image.png
deleted file mode 100644
index 24bdbb6..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-xhdpi/stat_notify_image_error.png
deleted file mode 100644
index 6ecd2d3..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image_error.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image.png
deleted file mode 100644
index 5e733ef..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image_error.png
deleted file mode 100644
index ecc2c83..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image_error.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml
new file mode 100644
index 0000000..4d2a35e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml
@@ -0,0 +1,45 @@
+<!--
+ Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="26.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M0 0h26v24H0z"
+ android:fillColor="#00000000"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M21.0,8.5
+ c0.85,0.0 1.6,0.23 2.3,0.62l2.24,-2.79
+ C25.1,5.96 20.26,2.0 13.0,2.0
+ S0.9,5.9 0.42,6.32
+ l12.57,15.6 4.21,-5.17
+ c-0.76,-0.87 -1.22,-2.0 -1.22,-3.25
+ c0.0,-2.76 2.24,-5.0 5.0,-5.0z"
+ android:fillAlpha=".3"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M21.0,10.0
+ c-1.93,0.0 -3.5,1.57 -3.5,3.5l1.75,0.0
+ c0.0,-0.9 0.78,-1.75 1.75,-1.75s1.7,0.78 1.75,1.75
+ c0.0,0.48 -0.2,0.92 -0.51,1.24l-1.09,1.1
+ c-0.6,0.63 -1.02,1.51 -1.02,2.47l0.0,0.44l1.75,0.0
+ c0.0,-1.3 0.39,-1.84 1.03,-2.47l0.78,-0.8
+ c0.5,-0.5 0.82,-1.2 0.82,-1.97
+ C24.5,11.57 22.93,10.0 21.0,10.0z
+ m-0.95,11.95l1.9,0.0l0.0,-1.9l-1.9,0.0l0.0,1.9z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_notify_image.xml b/packages/SystemUI/res/drawable/stat_notify_image.xml
new file mode 100644
index 0000000..c8745d7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_notify_image.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M21,19V5c0-1.1-0.9-2-2-2H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14C20.1,21,21,20.1,21,19z
+M8.5,13.5l2.5,3l3.5-4.5l4.5,6H5 L8.5,13.5z" />
+ <path
+ android:pathData="M0,0h24v24H0V0z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_notify_image_error.xml b/packages/SystemUI/res/drawable/stat_notify_image_error.xml
new file mode 100644
index 0000000..b929005
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_notify_image_error.xml
@@ -0,0 +1,30 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:pathData="M0,0h24v24H0V0z" />
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M17,18H5l3.5-4.5l2.5,3l3.3-4.5l2.7,3.8V8h4V5c0-1.1-0.9-2-2-2H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h12V18z" />
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M19.2,21H21v-1.8h-1.8V21z M19.2,9.9v7.4H21V9.9H19.2z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/tv_pip_button_focused.xml b/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
index 5cabb77..405ea0c 100644
--- a/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
+++ b/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
@@ -17,8 +17,8 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size
- android:width="36dp"
- android:height="36dp" />
+ android:width="34dp"
+ android:height="34dp" />
<solid
android:color="#4DFFFFFF" />
</shape>
diff --git a/core/res/res/layout/notification_action_list.xml b/packages/SystemUI/res/layout/qs_customize_tile_divider.xml
similarity index 65%
rename from core/res/res/layout/notification_action_list.xml
rename to packages/SystemUI/res/layout/qs_customize_tile_divider.xml
index 400decc..0d932ac 100644
--- a/core/res/res/layout/notification_action_list.xml
+++ b/packages/SystemUI/res/layout/qs_customize_tile_divider.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
+<!--
+ Copyright (C) 2016 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.
@@ -14,17 +15,11 @@
limitations under the License.
-->
-<LinearLayout
+<View
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/actions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:visibility="gone"
- android:layout_marginBottom="8dp"
- android:showDividers="middle"
- android:divider="?android:attr/listDivider"
- android:dividerPadding="12dp"
- >
- <!-- actions will be added here -->
-</LinearLayout>
+ android:layout_marginStart="16dp"
+ android:layout_marginEnd="16dp"
+ android:background="?android:attr/listDivider"
+ android:importantForAccessibility="no" />
diff --git a/packages/SystemUI/res/layout/recents_on_tv.xml b/packages/SystemUI/res/layout/recents_on_tv.xml
index 0f8c77c..28ea66d 100644
--- a/packages/SystemUI/res/layout/recents_on_tv.xml
+++ b/packages/SystemUI/res/layout/recents_on_tv.xml
@@ -31,18 +31,12 @@
android:focusable="true"
android:layoutDirection="rtl" />
+ <!-- Placeholder view to give focus to the PIP menus. -->
<View
- android:id="@+id/pip_shade"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="gone"
- android:background="#76000000" />
-
- <include
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="top|center_horizontal"
- android:layout_marginTop="132dp"
- layout="@layout/tv_pip_controls" />
+ android:id="@+id/pip"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:focusable="true"
+ android:visibility="gone" />
</com.android.systemui.recents.tv.views.RecentsTvView>
diff --git a/packages/SystemUI/res/layout/recents_stack_action_button.xml b/packages/SystemUI/res/layout/recents_stack_action_button.xml
index 2b2ce4e..625e9c1 100644
--- a/packages/SystemUI/res/layout/recents_stack_action_button.xml
+++ b/packages/SystemUI/res/layout/recents_stack_action_button.xml
@@ -18,7 +18,6 @@
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:gravity="start|center_vertical"
android:paddingStart="14dp"
android:paddingEnd="14dp"
android:paddingTop="12dp"
diff --git a/packages/SystemUI/res/layout/tv_pip_controls.xml b/packages/SystemUI/res/layout/tv_pip_controls.xml
index 2e0c9e7..563441f 100644
--- a/packages/SystemUI/res/layout/tv_pip_controls.xml
+++ b/packages/SystemUI/res/layout/tv_pip_controls.xml
@@ -17,13 +17,8 @@
*/
-->
-<com.android.systemui.tv.pip.PipControlsView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/pip_controls"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:orientation="horizontal">
+<!-- Layout for {@link com.android.systemui.tv.pip.PipControlsView}. -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="100dp"
@@ -98,4 +93,4 @@
android:textSize="12sp"
android:textColor="#EEEEEE" />
</LinearLayout>
-</com.android.systemui.tv.pip.PipControlsView>
+</merge>
diff --git a/packages/SystemUI/res/layout/tv_pip_menu.xml b/packages/SystemUI/res/layout/tv_pip_menu.xml
index c2c83ff..2647a99 100644
--- a/packages/SystemUI/res/layout/tv_pip_menu.xml
+++ b/packages/SystemUI/res/layout/tv_pip_menu.xml
@@ -26,7 +26,8 @@
android:gravity="top|center_horizontal"
android:clipChildren="false">
- <include
- layout="@layout/tv_pip_controls"
- android:clipChildren="false" />
+ <com.android.systemui.tv.pip.PipControlsView
+ android:id="@+id/pip_controls"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/tv_pip_overlay.xml b/packages/SystemUI/res/layout/tv_pip_overlay.xml
index c5c7e84..64bf3b5 100644
--- a/packages/SystemUI/res/layout/tv_pip_overlay.xml
+++ b/packages/SystemUI/res/layout/tv_pip_overlay.xml
@@ -38,25 +38,4 @@
android:gravity="center"
android:maxLines="2"
android:text="@string/pip_hold_home" />
- <LinearLayout
- android:id="@+id/guide_buttons"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_centerHorizontal="true"
- android:orientation="horizontal">
- <ImageView
- android:layout_width="19dp"
- android:layout_height="19dp"
- android:src="@drawable/ic_fullscreen_white_24dp" />
- <ImageView
- android:layout_width="19dp"
- android:layout_height="19dp"
- android:src="@drawable/ic_close_white" />
- <ImageView
- android:id="@+id/guide_button_play_pause"
- android:layout_width="19dp"
- android:layout_height="19dp"
- android:src="@drawable/ic_pause_white_24dp" />
- </LinearLayout>
</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml b/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml
new file mode 100644
index 0000000..1e464d8
--- /dev/null
+++ b/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:gravity="top|center_horizontal">
+
+ <com.android.systemui.tv.pip.PipRecentsControlsView
+ android:id="@+id/pip_controls"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent" />
+
+ <View
+ android:id="@+id/recents"
+ android:layout_width="1dp"
+ android:layout_height="1dp"
+ android:focusable="true" />
+</LinearLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 47d3bff..3fa6245 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Maak <xliff:g id="APP">%s</xliff:g> toe."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> verwerp."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle onlangse programme is toegemaak."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Begin tans <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Kennisgewing is toegemaak."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Tuis"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Onlangs"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Terug"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Kennisgewings"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Kortpadsleutels"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Wissel invoermetode"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Programme"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Bystand"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Blaaier"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakte"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-pos"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Kitsboodskappe"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musiek"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalender"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Wys saam met volumekontroles"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Moenie steur nie"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Volumeknoppieskortpad"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index f2afb8f..eb5d256 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> አስወግድ።"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ተሰናብቷል::"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ሁሉም የቅርብ ጊዜ ማመልከቻዎች ተሰናብተዋል።"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> በመጀመር ላይ።"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"ማሳወቂያ ተወግዷል።"</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"መነሻ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"የቅርብ ጊዜዎቹ"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ተመለስ"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"ማሳወቂያዎች"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"የቁልፍ ሰሌዳ አቋራጮች"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"የግቤት ስልት ቀይር"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"መተግበሪያዎች"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"ረዳት"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"አሳሽ"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"እውቂያዎች"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ኢሜይል"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"ፈጣን መልዕክት"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"ሙዚቃ"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"የቀን መቁጠሪያ"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"ከድምፅ መቆጣጠሪያዎች ጋር አሳይ"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"አትረብሽ"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"የድምፅ አዝራሮች አቋራጭ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index f949eaf..82a772c 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -172,6 +172,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"إزالة <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"تمت إزالة <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"تم تجاهل كل التطبيقات المستخدمة مؤخرًا."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"جارٍ بدء <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"تم تجاهل الإشعار."</string>
@@ -532,6 +534,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"الشاشة الرئيسية"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"الأحدث"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"رجوع"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"الإشعارات"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"اختصارات لوحة المفاتيح"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"تبديل أسلوب الإدخال"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"التطبيقات"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"التطبيق المساعد"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"المتصفح"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"جهات الاتصال"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"البريد الإلكتروني"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"الرسائل الفورية"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"الموسيقى"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"التقويم"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"عرض مع عناصر التحكم في مستوى الصوت"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"الرجاء عدم الإزعاج"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"اختصار أزرار مستوى الصوت"</string>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index 3aa911f..59b3141 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> kənarlaşdırın."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> çıxarıldı."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Bütün son tətbiqlər kənarlaşdırıldı."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> başlanır."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Bildiriş uzaqlaşdırıldı."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Əsas səhifə"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Sonuncular"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Geri"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Bildirişlər"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Klaviatura qısa yolları"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Daxiletmə metoduna keçin"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Tətbiqlər"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Yardım"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Brauzer"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktlar"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-poçt"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musiqi"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Təqvim"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Həcm nəzarəti ilə göstərin"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Narahat etməyin"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Səs düymələri qısayolu"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index cc091f6..0945885 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -169,6 +169,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Odbacite <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikacija <xliff:g id="APP">%s</xliff:g> je odbačena."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Sve nedavno korišćene aplikacije su odbačene."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Pokrećemo <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Obaveštenje je odbačeno."</string>
@@ -529,6 +531,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Početni"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nedavni sadržaj"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Nazad"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Obaveštenja"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Tasterske prečice"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Promeni metod unosa"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikacije"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Aplikacija za pomoć"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Pregledač"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakti"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Imejl"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Razmena trenutnih poruka"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muzika"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendar"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Prikaži sa kontrolama jačine zvuka"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne uznemiravaj"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Prečica za dugmad za jačinu zvuka"</string>
diff --git a/packages/SystemUI/res/values-be-rBY/strings.xml b/packages/SystemUI/res/values-be-rBY/strings.xml
index a496330..726a0e7 100644
--- a/packages/SystemUI/res/values-be-rBY/strings.xml
+++ b/packages/SystemUI/res/values-be-rBY/strings.xml
@@ -172,6 +172,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Выдаліць <xliff:g id="APP">%s</xliff:g> са спіса апошніх."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> выдалены."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Усе апошнія праграмы адхілены."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Запускаецца <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Апавяшчэнне прапушчана."</string>
@@ -532,6 +534,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Галоўная"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Апошнія"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Апавяшчэнні"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Спалучэнні клавіш для хуткага доступу"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Пераключэнне рэжыму ўводу"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Праграмы"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Памочнік"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Браўзер"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Кантакты"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Электронная пошта"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Iмгненныя паведамленнi"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Музыка"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Каляндар"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Паказаць з рэгулятарамі гучнасці"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не турбаваць"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Доступ праз кнопкі рэгулявання гучнасці"</string>
@@ -588,12 +602,12 @@
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Перамясціць управа"</string>
<string name="forced_resizable_info_text" msgid="7591061837558867999">"Праграма можа не працаваць у рэжыме некалькіх вокнаў"</string>
<string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Месца: <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Краніце двойчы, каб рэдагаваць."</string>
- <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>, краніце двойчы, каб дадаць."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Краніце двойчы, каб дадаць."</string>
<string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Месца: <xliff:g id="POSITION">%1$d</xliff:g>. Краніце двойчы, каб выбраць."</string>
<string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Перамясціць <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Выдаліць <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> дададзена ў наступнае месца: <xliff:g id="POSITION">%2$d</xliff:g>"</string>
- <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> выдалена"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Плітка <xliff:g id="TILE_NAME">%1$s</xliff:g> дададзена ў наступнае месца: <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Плітка <xliff:g id="TILE_NAME">%1$s</xliff:g> выдалена"</string>
<string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> перамешчана ў наступнае месца: <xliff:g id="POSITION">%2$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Рэдактар хуткіх налад."</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 1479bea..479087a 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Отхвърляне на <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Приложението <xliff:g id="APP">%s</xliff:g> е отхвърлено."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Всички скорошни приложения са отхвърлени."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> се стартира."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Известието е отхвърлено."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Начало"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Скорошни"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Известия"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Клавишни комбинации"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Превключване на метода на въвеждане"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Приложения"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Помощно приложение"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Браузър"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Контакти"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Електронна поща"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Незабавни съобщения"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Музика"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Календар"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Показване с контролите за силата на звука"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не безпокойте"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Пряк път към бутоните за силата на звука"</string>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index ed8b066..ccbcb6e 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> খারিজ করুন।"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> খারিজ করা হয়েছে৷"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"সমস্ত সাম্প্রতিক অ্যাপ্লিকেশন খারিজ করা হয়েছে।"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> তারাঙ্কিত করা হচ্ছে।"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"বিজ্ঞপ্তি খারিজ করা হয়েছে৷"</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"হোম"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"সাম্প্রতিকগুলি"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"পিছনে"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"বিজ্ঞপ্তিগুলি"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"কীবোর্ড শর্টকাট"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ইনপুট পদ্ধতি পাল্টান"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"অ্যাপ্লিকেশানগুলি"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"সহযোগিতা"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ব্রাউজার"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"পরিচিতি"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ইমেল"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"সংগীত"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"ক্যালেন্ডার"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"ভলিউম নিয়ন্ত্রণ সহ দেখান"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"বিরক্ত করবেন না"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"ভলিউম বোতামের শর্টকাট"</string>
diff --git a/packages/SystemUI/res/values-bs-rBA/strings.xml b/packages/SystemUI/res/values-bs-rBA/strings.xml
index c620178..f1be672 100644
--- a/packages/SystemUI/res/values-bs-rBA/strings.xml
+++ b/packages/SystemUI/res/values-bs-rBA/strings.xml
@@ -169,6 +169,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Odbaci aplikaciju <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikacija <xliff:g id="APP">%s</xliff:g> uklonjena."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Sve nedavno korištene aplikacije su odbačene."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Pokrećem aplikaciju <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Obavještenje je uklonjeno."</string>
@@ -529,6 +531,30 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Početak"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nedavni ekrani"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Nazad"</string>
+ <!-- no translation found for keyboard_shortcut_group_system_notifications (8366964080041773224) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_system_shortcuts_helper (4892255911160332762) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_system_switch_input (2334164096341310324) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications (9129465955073449206) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_assist (9095441910537146013) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_browser (6465985474000766533) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_contacts (2064197111278436375) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_email (6257036897441939004) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_im (1892749399083161405) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_music (4775559515850922780) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_youtube (6555453761294723317) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_calendar (9043614299194991263) -->
+ <skip />
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Prikazati sa kontrolama jačine zvuka"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne ometaj"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Prečica za dugmad za Jačinu zvuka"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 0145c2a..b7fffb7 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ignora <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"S\'ha omès <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"S\'han descartat totes les aplicacions recents."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"S\'està iniciant <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificació omesa."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Inici"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recents"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Enrere"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notificacions"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Tecles de drecera"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Canvia el mètode d\'introducció"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplicacions"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistència"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navegador"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contactes"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Correu electrònic"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"MI"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Music"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendari"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostra amb els controls de volum"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"No molesteu"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Drecera per als botons de volum"</string>
@@ -583,13 +597,13 @@
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mou a l\'esquerra"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mou a la dreta"</string>
<string name="forced_resizable_info_text" msgid="7591061837558867999">"És possible que l\'aplicació no funcioni amb el Mode multifinestra"</string>
- <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posició <xliff:g id="POSITION">%1$d</xliff:g>, mosaic <xliff:g id="TILE_NAME">%2$s</xliff:g>. Fes doble toc per editar-la."</string>
- <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"Mosaic <xliff:g id="TILE_NAME">%1$s</xliff:g>. Fes doble toc per afegir-lo."</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posició <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Fes doble toc per editar-la."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Fes doble toc per afegir-ho."</string>
<string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posició <xliff:g id="POSITION">%1$d</xliff:g>. Fes doble toc per seleccionar-la."</string>
- <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Mou el mosaic <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Suprimeix el mosaic <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"El mosaic <xliff:g id="TILE_NAME">%1$s</xliff:g> s\'ha afegit a la posició <xliff:g id="POSITION">%2$d</xliff:g>"</string>
- <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"El mosaic <xliff:g id="TILE_NAME">%1$s</xliff:g> s\'ha suprimit"</string>
- <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"El mosaic <xliff:g id="TILE_NAME">%1$s</xliff:g> s\'ha mogut a la posició <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Mou <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Suprimeix <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> s\'ha afegit a la posició <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> s\'ha suprimit"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> s\'ha mogut a la posició <xliff:g id="POSITION">%2$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor de la configuració ràpida."</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index ec2011f..b707ece 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -170,6 +170,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Zavřít aplikaci <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikace <xliff:g id="APP">%s</xliff:g> byla odebrána."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Všechny naposledy použité aplikace byly odstraněny."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Spouštění aplikace <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Oznámení je zavřeno."</string>
@@ -530,6 +532,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Plocha"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Poslední"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Zpět"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Oznámení"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Klávesové zkratky"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Přepnout metodu zadávání"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikace"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Asistence"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Prohlížeč"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakty"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Chat"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Hudba"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendář"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Zobrazit včetně ovládacích prvků hlasitosti"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Nerušit"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Zkratka tlačítek hlasitosti"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 8711100..7a25141 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Afvis <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> er annulleret."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle de seneste applikationer er lukket."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> startes."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Underretningen er annulleret."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Start"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Seneste"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Tilbage"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Underretninger"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Tastaturgenveje"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Skift indtastningsmetode"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applikationer"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistance"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktpersoner"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Chat"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musik"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalender"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Vis med lydstyrkeregulering"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Forstyr ikke"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Genvej til lydstyrkeknapper"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 2daa00f..e10eb64 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> beenden"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> entfernt"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle kürzlich verwendeten Apps wurden entfernt."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> wird gestartet."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Benachrichtigung geschlossen"</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Startseite"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Letzte"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Zurück"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Benachrichtigungen"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Tastenkombinationen"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Eingabemethode wechseln"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Apps"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistent"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakte"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-Mail"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Music"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalender"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Einschließlich Lautstärkeregler anzeigen"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Bitte nicht stören"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Tastenkombination für Lautstärketasten"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 34385f3..5ec3133 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Παράβλεψη <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Απορρίφθηκαν <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Έγινε παράβλεψη όλων των πρόσφατων εφαρμογών."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Έναρξη <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Η ειδοποίηση έχει απορριφθεί."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Αρχική οθόνη"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Πρόσφατα"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Πίσω"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Ειδοποιήσεις"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Συντομεύσεις πληκτρολογίου"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Εναλλαγή μεθόδου εισαγωγής"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Εφαρμογές"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Υποβοήθηση"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Πρόγραμμα περιήγησης"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Επαφές"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Ηλεκτρονικό ταχυδρομείο"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Άμεσα μηνύματα (ΙΜ)"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Μουσική"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Ημερολόγιο"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Εμφάνιση με στοιχεία ελέγχου έντασης ήχου"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Μην ενοχλείτε"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Συντόμευση κουμπιών έντασης ήχου"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 71a8ad7..f08894f 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Dismiss <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> dismissed."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"All recent applications dismissed."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Starting <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification dismissed."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Home"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recent"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Back"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifications"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Keyboard Shortcuts"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Switch input method"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applications"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assist"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contacts"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Music"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendar"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Show with volume controls"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Do not disturb"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Volume buttons shortcut"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 71a8ad7..f08894f 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Dismiss <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> dismissed."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"All recent applications dismissed."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Starting <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification dismissed."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Home"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recent"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Back"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifications"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Keyboard Shortcuts"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Switch input method"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applications"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assist"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contacts"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Music"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendar"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Show with volume controls"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Do not disturb"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Volume buttons shortcut"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 71a8ad7..f08894f 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Dismiss <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> dismissed."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"All recent applications dismissed."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Starting <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification dismissed."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Home"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recent"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Back"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifications"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Keyboard Shortcuts"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Switch input method"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applications"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assist"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contacts"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Music"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendar"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Show with volume controls"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Do not disturb"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Volume buttons shortcut"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 35d0f47..b5a10e1 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Rechazar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> descartada."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Se descartaron todas las aplicaciones recientes."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificación ignorada"</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Pantalla principal"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recientes"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Atrás"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notificaciones"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Combinación de teclas"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Cambiar método de entrada"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplicaciones"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Asistencia"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navegador"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contactos"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Correo electrónico"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"MI"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Música"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendario"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar con controles de volumen"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"No interrumpir"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Combinación de teclas de botones de volumen"</string>
@@ -582,7 +596,7 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover hacia arriba"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover a la izquierda"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover a la derecha"</string>
- <string name="forced_resizable_info_text" msgid="7591061837558867999">"Es posible que la app no funcione con la función Multiventana"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Es posible que la app no se ejecute con la función Multiventana"</string>
<string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posición <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Presiona dos veces para editarla."</string>
<string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Presiona dos veces para agregarlo."</string>
<string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posición <xliff:g id="POSITION">%1$d</xliff:g>. Presiona dos veces para seleccionarla."</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index a976a9c..d8affc9 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ignorar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Se ha eliminado <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Se han ignorado todas las aplicaciones recientes."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificación ignorada"</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Inicio"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recientes"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Atrás"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notificaciones"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Combinaciones de teclas"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Cambiar método de introducción"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplicaciones"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Asistencia"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navegador"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contactos"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Correo electrónico"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"MI"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Música"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendario"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar con controles de volumen"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"No molestar"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Combinación de teclas para los botones de volumen"</string>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index e7bfdff..f18bf05 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Rakendusest <xliff:g id="APP">%s</xliff:g> loobumine."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Loobusite rakendusest <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Kõikidest hiljutistest rakendustest on loobutud"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Rakenduse <xliff:g id="APP">%s</xliff:g> käivitamine."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g>, <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Märguandest on loobutud."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Avaekraan"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Hiljutised"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Tagasi"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Märguanded"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Klaviatuuri otseteed"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Sisestusmeetodi vahetamine"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Rakendused"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Abi"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Brauser"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktid"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-post"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM (kiirsuhtlus)"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muusika"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalender"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Kuva koos helitugevuse juhtnuppudega"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Mitte segada"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Helitugevuse nuppude otsetee"</string>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index b9cb78e..575f8749 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Baztertu <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> baztertu da."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Azken aplikazio guztiak baztertu da."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> hasten."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Jakinarazpena baztertu da."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Hasierako pantaila"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Azkenak"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Atzera"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Jakinarazpenak"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Lasterbideak"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Aldatu idazketa-metodoa"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikazioak"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Laguntzailea"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Arakatzailea"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktuak"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Helbide elektronikoa"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Istanteko mezularitza"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musika"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Egutegia"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Erakutsi bolumena kontrolatzeko aukerekin"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ez molestatu"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Bolumen-botoietarako lasterbidea"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index af74435..7c2da10 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"رد کردن <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> نادیده گرفته شد."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"همه برنامههای اخیر رد شدند."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> در حال شروع به کار است."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"اعلان ردشد."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"صفحه اصلی"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"موارد اخیر"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"برگشت"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"اعلانها"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"میانبرهای صفحهکلید"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"تغییر روش ورودی"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"برنامهها"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"همیار"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"مرورگر"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"مخاطبین"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"رایانامه"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"پیام فوری"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"موسیقی"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"تقویم"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"نمایش با کنترلهای صدا"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"مزاحم نشوید"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"میانبر دکمههای صدا"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 3b28199..6db0a3e 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Hylätään <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> hylättiin."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Kaikki viimeisimmät sovellukset on hylätty."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Käynnistetään <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Ilmoitus hylätty."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Aloitusnäyttö"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Viimeaikaiset"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Takaisin"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Ilmoitukset"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Pikanäppäimet"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Vaihda syöttötapaa"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Sovellukset"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Apusovellus"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Selain"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Yhteystiedot"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Sähköposti"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Pikaviesti"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musiikki"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalenteri"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Näytä äänenvoimakkuuden säätimien yhteydessä"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Älä häiritse"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Äänenvoimakkuuspainikkeiden pikanäppäin"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 2ef24db..89c6826 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Supprimer <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Application \"<xliff:g id="APP">%s</xliff:g>\" ignorée."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Toutes les applications récentes ont été supprimées."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Lancement de <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification masquée"</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Accueil"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Récents"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Précédent"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifications"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Raccourcis clavier"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Changer de méthode d\'entrée"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applications"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistance"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navigateur"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contacts"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Courriel"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"MI"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musique"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Agenda"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Afficher avec les commandes de volume"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne pas déranger"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Raccourci des boutons de volume"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 93d9e14..2f99b94 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Supprimer <xliff:g id="APP">%s</xliff:g>"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Application \"<xliff:g id="APP">%s</xliff:g>\" ignorée."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Toutes les applications récentes ont été supprimées."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Lancement de <xliff:g id="APP">%s</xliff:g>"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> : <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification masquée"</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Accueil"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Récents"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Précédent"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifications"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Raccourcis clavier"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Changer le mode de saisie"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applications"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistance"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navigateur"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contacts"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Messagerie"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Messagerie instantanée"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musique"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Agenda"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Afficher avec les commandes de volume"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne pas déranger"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Raccourci des boutons de volume"</string>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 86a0bfa..c8f6649 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Rexeitar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Rexeitouse <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Rexeitáronse todas as aplicacións recentes."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificación rexeitada"</string>
@@ -528,6 +530,30 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Inicio"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recentes"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Volver"</string>
+ <!-- no translation found for keyboard_shortcut_group_system_notifications (8366964080041773224) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_system_shortcuts_helper (4892255911160332762) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_system_switch_input (2334164096341310324) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications (9129465955073449206) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_assist (9095441910537146013) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_browser (6465985474000766533) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_contacts (2064197111278436375) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_email (6257036897441939004) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_im (1892749399083161405) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_music (4775559515850922780) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_youtube (6555453761294723317) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_calendar (9043614299194991263) -->
+ <skip />
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar cos controis de volume"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Non molestar"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Atallo dos botóns de volume"</string>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index d52226d..ef6a49c 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> કાઢી નાખો."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> કાઢી નાખી."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"તમામ તાજેતરની એપ્લિકેશનો કાઢી નાખી."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> પ્રારંભ કરી રહ્યું છે."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"સૂચના કાઢી નાખી."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"હોમ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"તાજેતરના"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"પાછળ"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"સૂચનાઓ"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"કીબોર્ડ શૉર્ટકટ્સ"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ઇનપુટ પદ્ધતિ સ્વિચ કરો"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"ઍપ્લિકેશનો"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"સહાય"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"બ્રાઉઝર"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"સંપર્કો"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ઇમેઇલ"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"સંગીત"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"કૅલેન્ડર"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"વૉલ્યૂમ નિયંત્રણ સાથે બતાવો"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ખલેલ પાડશો નહીં"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"વૉલ્યૂમ બટન્સ શૉર્ટકટ"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 160d4a0..1ba0caf 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> को ख़ारिज करें."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> खा़रिज कर दिया गया."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"हाल ही के सभी ऐप्लिकेशन ख़ारिज कर दिए गए."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> प्रारंभ हो रहा है."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"नोटिफिकेशन खारिज की गई."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"होम"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"हाल ही के"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"वापस जाएं"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"नोटिफ़िकेशन"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"कीबोर्ड शॉर्टकट"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"इनपुट पद्धति बदलें"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"ऐप्लिकेशन"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"सहायक"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ब्राउज़र"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"संपर्क"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ईमेल"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"संगीत"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"कैलेंडर"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"वॉल्यूम नियंत्रणों के साथ दिखाएं"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"परेशान न करें"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"वॉल्यूम बटन का शॉर्टकट"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index ddfcb55..81c6276 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -169,6 +169,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Odbacivanje aplikacije <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikacija <xliff:g id="APP">%s</xliff:g> odbačena je."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Odbačene su sve nedavne aplikacije."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Pokretanje aplikacije <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Obavijest je odbačena."</string>
@@ -529,6 +531,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Početni zaslon"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Najnovije"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Natrag"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Obavijesti"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Tipkovni prečaci"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Promjena načina unosa"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikacije"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Pomoć"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Preglednik"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakti"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-pošta"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Izravna poruka"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Glazba"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendar"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Prikaži s kontrolama glasnoće"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne uznemiravaj"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Prečac tipki za glasnoću"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index c026926..b7ac8a4 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"A(z) <xliff:g id="APP">%s</xliff:g> elvetése."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> eltávolítva."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Az összes alkalmazás eltávolítva a nemrég használtak közül."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"A(z) <xliff:g id="APP">%s</xliff:g> indítása."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Értesítés elvetve."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Otthon"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Legutóbbiak"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Vissza"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Értesítések"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Billentyűkódok"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Beviteli mód váltása"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Alkalmazások"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Segédalkalmazás"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Böngésző"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Névjegyek"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Azonnali üzenetküldés"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Zene"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Naptár"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Megjelenítés hangerőszabályzóval"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne zavarjanak"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"A hangerőgombok gyorsbillentyűk"</string>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index a9d122a..7e4e01a 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Անտեսել <xliff:g id="APP">%s</xliff:g>-ը:"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g>-ը անտեսված է:"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Բոլոր վերջին հավելվածները հեռացվել են ցուցակից:"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Մեկնարկել <xliff:g id="APP">%s</xliff:g>-ը:"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Ծանուցումը անտեսվեց:"</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Գլխավոր էջ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Վերջինները"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Հետ"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Ծանուցումներ"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Ստեղնային դյուրանցումներ"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Փոխարկել մուտքագրման եղանակը"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Գործադիրներ"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Օգնություն"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Դիտարկիչ"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Կոնտակտներ"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Էլփոստ"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Երաժշտություն"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Օրացույց"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Ցույց տալ ձայնի ուժգնության կառավարման տարրերի հետ"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Չընդհատել"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Ձայնի կոճակների դյուրանցում"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 876034c..2b51426 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Menyingkirkan <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> disingkirkan."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Semua aplikasi terbaru telah ditutup."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Memulai <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notifikasi disingkirkan."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Layar Utama"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Terbaru"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Kembali"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifikasi"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Pintasan Keyboard"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Beralih metode masukan"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikasi"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Bantuan"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontak"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musik"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalender"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Tampilkan dengan kontrol volume"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Jangan ganggu"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Pintasan tombol volume"</string>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index 4ce5f54..1dc37df 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Hunsa <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> vísað frá."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Öll nýleg forrit fjarlægð."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Ræsir <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Tilkynningu lokað."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Heim"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nýlegt"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Til baka"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Tilkynningar"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Flýtilyklar"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Skipta um innsláttaraðferð"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Forrit"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Aðstoð"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Vafri"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Tengiliðir"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Tölvupóstur"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Spjall"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Tónlist"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Dagatal"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Sýna með hljóðstyrksstillingum"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ónáðið ekki"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Flýtihnappar fyrir hljóðstyrk"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 62c18f2..4a8ba99 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Elimina <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> eliminata."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Tutte le applicazioni recenti sono state rimosse."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Avvio di <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notifica eliminata."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Home"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recenti"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Indietro"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifiche"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Scorciatoie da tastiera"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Cambia metodo di immissione"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applicazioni"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistenza"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contatti"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Chat"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musica"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendario"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostra con controlli volume"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Non disturbare"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Pulsanti del volume come scorciatoia"</string>
@@ -585,7 +599,7 @@
<string name="forced_resizable_info_text" msgid="7591061837558867999">"L\'app potrebbe non funzionare con la modalità multi-finestra"</string>
<string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posizione <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Tocca due volte per modificare."</string>
<string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Tocca due volte per aggiungere."</string>
- <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Positione <xliff:g id="POSITION">%1$d</xliff:g>. Tocca due volte per selezionare."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posizione <xliff:g id="POSITION">%1$d</xliff:g>. Tocca due volte per selezionare."</string>
<string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Sposta <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Rimuovi <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Il riquadro <xliff:g id="TILE_NAME">%1$s</xliff:g> è stato aggiunto alla posizione <xliff:g id="POSITION">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 097b427..d41d50d 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -170,6 +170,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"סגור את <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> נדחה."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"כל האפליקציות האחרונות נסגרו."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"מפעיל את <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"הודעה נדחתה."</string>
@@ -530,6 +532,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"דף הבית"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"אחרונים"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"הקודם"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"הודעות"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"מקשי קיצור במקלדת"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"החלפת שיטת קלט"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"אפליקציות"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"מסייע"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"דפדפן"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"אנשי קשר"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"אימייל"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"שליחת הודעות מיידיות"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"מוזיקה"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"יומן"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"הצג עם פקדי עוצמת הקול"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"נא לא להפריע"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"מקש קיצור ללחצני עוצמת קול"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 61ff6d4..83a9888 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>を削除します。"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g>は削除されました。"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"最近のアプリケーションをすべて消去しました。"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>を開始しています。"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"通知が削除されました。"</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ホーム"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"最近"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"戻る"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"通知"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"キーボード ショートカット"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"入力方法の切り替え"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"アプリ"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"アシスト"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ブラウザ"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"連絡先"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"メール"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"音楽"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"カレンダー"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"音量調節を表示"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"通知の非表示"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"音量ボタンのショートカット"</string>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 26f25293..5008fe0 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>-ის უგულებელყოფა."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ამოშლილია სიიდან."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ყველა ბოლო აპლიკაცია გაუქმდა."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> იწყება."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"შეტყობინება წაიშალა."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"მთავარი"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ბოლოს გამოყენებული"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"უკან"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"შეტყობინებები"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"კლავიატურის მალსახმობები"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"შეყვანის მეთოდის გადართვა"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"აპლიკაციები"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"დახმარება"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ბრაუზერი"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"კონტაქტები"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ელფოსტა"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"მუსიკა"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"კალენდარი"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"ხმის მართვის საშუალებების ჩვენება"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"არ შემაწუხოთ"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"ხმის ღილაკების მალსახმობი"</string>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 737041e..ff33f05 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> қолданбасынан бас тарту."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> алынып тасталған."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Барлық жақындағы қабылданбаған қолданбалар."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> іске қосылуда."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Хабар алынып тасталды."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Негізгі бет"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Жақындағылар"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Артқа"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Хабарландырулар"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Пернелер тіркесімдері"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Енгізу әдісін ауыстыру"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Қолданбалар"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Көмекші"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Браузер"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Контактілер"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Электрондық пошта"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Mузыка"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Күнтізбе"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Дыбыс деңгейін басқару элементтерімен бірге көрсету"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Мазаламау"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Дыбыс деңгейі түймелерінің төте жолы"</string>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 1cec0b0..b69f893 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"បោះបង់ <xliff:g id="APP">%s</xliff:g> ។"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> បដិសេធ។"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"កម្មវិធីថ្មីៗទាំងអស់ត្រូវបានបោះបង់។"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"ចាប់ផ្ដើម <xliff:g id="APP">%s</xliff:g> ។"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"បានបដិសេធការជូនដំណឹង"</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ដើម"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ថ្មីៗ"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ថយក្រោយ"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"ការជូនដំណឹង"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"ផ្លូវកាត់ក្ដារចុច"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ប្ដូរវិធីសាស្ត្របញ្ចូល"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"កម្មវិធី"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"ជំនួយ"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"កម្មវិធីរុករក"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"ទំនាក់ទំនង"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"អ៊ីមែល"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"តន្ត្រី"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"ប្រតិទិន"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"បង្ហាញជាមួយការគ្រប់គ្រងកម្រិតសំឡេង"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"កុំរំខាន"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"ផ្លូវកាត់ប៊ូតុងកម្រិតសំឡេង"</string>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index 2eb6141..1ce14dd5 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> ವಜಾಗೊಳಿಸು."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ವಜಾಗೊಳಿಸಲಾಗಿದೆ."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ಇತ್ತೀಚಿನ ಎಲ್ಲಾ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ವಜಾಗೊಳಿಸಲಾಗಿದೆ."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ಪ್ರಾರಂಭಿಸಲಾಗುತ್ತಿದೆ."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"ಅಧಿಸೂಚನೆ ವಜಾಗೊಂಡಿದೆ."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ಮುಖಪುಟ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ಇತ್ತೀಚಿನವುಗಳು"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ಹಿಂದೆ"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"ಅಧಿಸೂಚನೆಗಳು"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್ಕಟ್ಗಳು"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ಇನ್ಪುಟ್ ವಿಧಾನ ಬದಲಿಸಿ"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"ಅಪ್ಲಿಕೇಶನ್ಗಳು"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"ಸಹಾಯ ಮಾಡು"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ಬ್ರೌಸರ್"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"ಸಂಪರ್ಕಗಳು"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ಇಮೇಲ್"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"ಸಂಗೀತ"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"ಕ್ಯಾಲೆಂಡರ್"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"ವಾಲ್ಯೂಮ್ ನಿಯಂತ್ರಣಗಳ ಜೊತೆಗೆ ತೋರಿಸು"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"ವಾಲ್ಯೂಮ್ ಬಟನ್ಗಳ ಶಾರ್ಟ್ಕಟ್"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index ae60d0e..a8a2a0a 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>을(를) 숨깁니다."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g>이(가) 제거되었습니다."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"최근 사용한 애플리케이션을 모두 닫았습니다."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>을(를) 시작하는 중입니다."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"알림이 제거되었습니다."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"홈"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"최근"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"뒤로"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"알림"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"단축키"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"입력 방법 전환"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"애플리케이션"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"지원"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"브라우저"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"주소록"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"이메일"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"메신저"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"음악"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"캘린더"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"볼륨 컨트롤과 함께 표시"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"알림 일시중지"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"볼륨 버튼 단축키"</string>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index b035bbb..6a2d77f 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> этибарга албоо."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> жок болду."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Акыркы колдонмолордун баары көз жаздымда калтырылды."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> иштеп баштоодо."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Эскертме жок кылынды."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Башкы бет"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Акыркылар"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Артка"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Эскертмелер"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Баскычтоптун кыска жолдору"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Киргизүү ыкмасын которуштуруу"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Колдонмолор"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Көмөкчү"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Серепчи"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Байланыштар"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Электрондук почта"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Музыка"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Жылнаама"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Үн көзөмөлдөгүчтөрү менен көрсөтүлсүн"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Тынчымды алба"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Үндү көзөмөлдөөчү баскычтардын кыска жолдору"</string>
@@ -582,7 +596,7 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Жогору жылдыруу"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Солго жылдыруу"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Оңго жылдыруу"</string>
- <string name="forced_resizable_info_text" msgid="7591061837558867999">"Көп терезе режиминде колдонмо иштебей калышы мүмкүн"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Бир нече терезе режиминде колдонмо иштебей калышы мүмкүн"</string>
<string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Орду - <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Түзөтүү үчүн эки жолу таптаңыз."</string>
<string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Кошуу үчүн эки жолу таптаңыз."</string>
<string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Орду - <xliff:g id="POSITION">%1$d</xliff:g>. Тандоо үчүн эки жолу таптаңыз."</string>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 2355a84..601cc2a 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"ປິດ <xliff:g id="APP">%s</xliff:g> ໄວ້."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"ປິດ <xliff:g id="APP">%s</xliff:g> ແລ້ວ."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ທຸກແອັບພລິເຄຊັນບໍ່ດົນມານີ້ຖືກປ່ອຍໄປ."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"ກຳລັງເປີດ <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"ປິດການແຈ້ງເຕືອນແລ້ວ."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ໜ້າຫຼັກ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ຫາກໍໃຊ້"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ກັບຄືນ"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"ການແຈ້ງເຕືອນ"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"ປຸ່ມລັດແປ້ນພິມ"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ສະລັບຮູບແບບການປ້ອນຂໍ້ມູນ"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"ແອັບພລິເຄຊັນ"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"ຕົວຊ່ວຍ"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ໂປຣແກຣມທ່ອງເວັບ"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"ລາຍຊື່ຜູ້ຕິດຕໍ່"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ອີເມວ"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"ດົນຕີ"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"ປະຕິທິນ"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"ສະແດງສ່ວນຄວບຄຸມສຽງ"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ຫ້າມລົບກວນ"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"ທາງລັດປຸ່ມສຽງ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 93c0b69..866abf3 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -170,6 +170,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Atsisakyti <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Atsisakyta programos „<xliff:g id="APP">%s</xliff:g>“."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Atsisakyta visų naujausių programų."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Paleidžiama <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"„<xliff:g id="APP">%1$s</xliff:g>“ <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Pranešimo atsisakyta."</string>
@@ -530,6 +532,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Pagrindinis ekranas"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Naujausios veiklos ekranas"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Atgal"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Pranešimai"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Spartieji klavišai"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Perjungti įvesties metodą"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Programos"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Pagalbinė programa"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Naršyklė"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktai"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"El. paštas"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"TP"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muzika"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendorius"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Rodyti su garsumo valdikliais"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Netrukdymo režimas"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Garsumo mygtukų spartusis klavišas"</string>
@@ -590,7 +604,7 @@
<string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g> padėtis. Dukart palieskite, kad pasirinktumėte."</string>
<string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Perkelti išklotinės elementą „<xliff:g id="TILE_NAME">%1$s</xliff:g>“"</string>
<string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Pašalinti išklotinės elementą „<xliff:g id="TILE_NAME">%1$s</xliff:g>“"</string>
- <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Išklotinės elementas „<xliff:g id="TILE_NAME">%1$s</xliff:g>“ pridėtas prie <xliff:g id="POSITION">%2$d</xliff:g> pozicijos"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Išklotinės elementas „<xliff:g id="TILE_NAME">%1$s</xliff:g>“ pridėtas prie <xliff:g id="POSITION">%2$d</xliff:g> padėties"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Išklotinės elementas „<xliff:g id="TILE_NAME">%1$s</xliff:g>“ pašalintas"</string>
<string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Išklotinės elementas „<xliff:g id="TILE_NAME">%1$s</xliff:g>“ perkeltas į <xliff:g id="POSITION">%2$d</xliff:g> padėtį"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Sparčiųjų nustatymų redagavimo priemonė."</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 0ee306b..9c32b31 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -169,6 +169,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Nerādīt lietotni <xliff:g id="APP">%s</xliff:g>"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Lietotne <xliff:g id="APP">%s</xliff:g> vairs netiek rādīta."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Visas nesen izmantotās lietojumprogrammas tika noņemtas."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Notiek lietotnes <xliff:g id="APP">%s</xliff:g> palaišana."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Paziņojums netiek rādīts."</string>
@@ -529,6 +531,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Sākums"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Pēdējie"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Atpakaļ"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Paziņojumi"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Īsinājumtaustiņi"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Pārslēgt ievades metodi"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Lietojumprogrammas"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Palīgs"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Pārlūkprogramma"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktpersonas"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-pasts"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Tūlītējā ziņojumapmaiņa"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Mūzika"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendārs"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Rādīt ar skaļuma vadīklām"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Netraucēt"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Skaļuma pogu saīsne"</string>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index cfacc43..7f2fc15 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Отфрли <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> е отфрлена."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Сите неодамнешни апликации се отфрлени."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Се стартува <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Известувањето е отфрлено."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Почетна страница"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Неодамнешни"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Известувања"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Кратенки на тастатурата"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Префрли метод за внесување"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Апликации"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Помош"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Прелистувач"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Контакти"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Е-пошта"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Музика"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Календар"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Прикажи со контроли за јачина на звук"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не вознемирувај"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Кратенка за копчињата за јачина на звук"</string>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index deca898..dfe992c 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> നിരസിക്കുക."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> നിരസിച്ചു."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"അടുത്തിടെയുള്ള എല്ലാ അപ്ലിക്കേഷനും നിരസിച്ചു."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ആരംഭിക്കുന്നു."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"അറിയിപ്പ് നിരസിച്ചു."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"വീട്"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"പുതിയവ"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"മടങ്ങുക"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"അറിയിപ്പുകൾ"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"കീബോർഡ് കുറുക്കുവഴികൾ"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ടൈപ്പിംഗ് രീതി മാറുക"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"അപ്ലിക്കേഷനുകൾ"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"അസിസ്റ്റ്"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ബ്രൗസർ"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"കോൺടാക്റ്റുകൾ"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ഇമെയിൽ"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"സംഗീതം"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"കലണ്ടർ"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"വോളിയം നിയന്ത്രണങ്ങളോടൊപ്പം കാണിക്കുക"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ശല്യപ്പെടുത്തരുത്"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"വോളിയം ബട്ടൺ കുറുക്കുവഴി"</string>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index b701e21..80cb8f2 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -166,6 +166,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>-г хаах."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> байхгүй."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Хамгийн сүүлийн бүх програмыг арилгасан байна."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>-г эхлүүлж байна."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Мэдэгдэл хаагдсан."</string>
@@ -526,6 +528,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Нүүр хуудас"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Саяхны"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Буцах"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Мэдэгдэл"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Гарын товчлол"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Оролтын аргыг солих"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Апп"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Дэмжлэг"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Хөтөч"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Харилцагчид"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Имэйл"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Хөгжим"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Хуанли"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Түвшний хяналттай харуулах"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Бүү саад бол"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Түвшний товчлуурын товчлол"</string>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 6c6e634..76dfcd5 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> डिसमिस करा."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> डिसमिस केला."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"अलीकडील सर्व अनुप्रयोग डिसमिस झाले."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> प्रारंभ करीत आहे."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"सूचना डिसमिस केल्या."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"मुख्यपृष्ठ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"अलीकडील"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"परत"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"सूचना"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"कीबोर्ड शॉर्टकट"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"इनपुट पद्धत स्विच करा"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"अनुप्रयोग"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"सहाय्य"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ब्राउझर"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"संपर्क"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ईमेल"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"संगीत"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"कॅलेंडर"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"आवाज नियंत्रणांसह दर्शवा"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"व्यत्यय आणू नका"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"आवाजाच्या बटणांचा शार्टकट"</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 335ff4c..9401198 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ketepikan <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ditolak."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Semua aplikasi terbaharu diketepikan."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Memulakan <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Pemberitahuan diketepikan."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Skrin Utama"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Terbaharu"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Kembali"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Pemberitahuan"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Pintasan Papan Kekunci"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Tukar kaedah input"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikasi"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Bantu"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Penyemak imbas"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kenalan"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mel"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muzik"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendar"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Tunjukkan dengan kawalan kelantangan"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Jangan ganggu"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Pintasan butang kelantangan"</string>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index d309991..6964750 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>ကို ပယ်လိုက်ရန်"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ထုတ်ထားသည်။"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"မကြာသေးမီက အပလီကေးရှင်းများအားလုံး ဖယ်ထုတ်ပြီးပါပြီ။"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>ကို စတင်နေသည်။"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g><xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"အကြောင်းကြားချက်ကိုဖယ်ရှားပြီး"</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ပင်မ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"မကြာသေးခင်က"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"နောက်သို့"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"အကြောင်းကြားချက်များ"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"ကီးဘုတ် ဖြတ်လမ်းများ"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ထည့်သွင်းမှုနည်းလမ်းကို ပြောင်းလဲပါ"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"အက်ပ်များ"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"အထောက်အကူ"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ဘရောင်ဇာ"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"အဆက်အသွယ်များ"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"အီးမေးလ်"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"အမြန်စာတိုစနစ်"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Music"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"ပြက္ခဒိန်"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"အသံထိန်းချုပ်သည့်ခလုတ်များဖြင့် ပြပါ"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"မနှောက်ယှက်ပါနှင့်"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"အသံထိန်းချုပ်သည့်ခလုတ် ဖြတ်လမ်း"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 8a961fc..220250b 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Avvis <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> avvist."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle nylig brukte apper er avvist."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Starter <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Varselet ble skjult."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Startside"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nylige"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Tilbake"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Varsler"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Hurtigtaster"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Bytt inndatametode"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Apper"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assist"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Nettleser"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakter"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-post"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Chat"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musikk"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalender"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Vis med volumkontrollene"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ikke forstyrr"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Hurtigtast for volumknappene"</string>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 7e91a53..836dc4b 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> खारेज गर्नुहोस्।"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> खारेज गरिएको छ।"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"सबै हालका अनुप्रयोगहरू खारेज गरियो।"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>सुरु गर्दै।"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"सूचना खारेज।"</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"गृह"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"हालैका"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"पछाडि"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"सूचनाहरू"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"किबोर्ड सर्टकटहरू"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"इनपुट विधिलाई स्विच गर्नुहोस्"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"अनुप्रयोगहरू"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"सहायता"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ब्राउजर"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"सम्पर्कहरू"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"इमेल"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"संगीत"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"पात्रो"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"भोल्युम नियन्त्रणसहित देखाउनुहोस्"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"बाधा नपुर्याउनुहोस्"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"भोल्युम बटनका सर्टकट"</string>
@@ -582,7 +596,7 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"माथि सार्नुहोस्"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"बाँया सार्नुहोस्"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"दायाँ सार्नुहोस्"</string>
- <string name="forced_resizable_info_text" msgid="7591061837558867999">"अनुप्रयोगले बहु-विन्डोमा काम नगर्न सक्छ"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"अनुप्रयोग बहु-विन्डोमा काम नगर्न सक्छ"</string>
<string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"स्थिति <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>। सम्पादन गर्नका लागि डबल ट्याप गर्नुहोस्।"</string>
<string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>। थप्नका लागि डबल ट्याप गर्नुहोस्।"</string>
<string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"स्थिति <xliff:g id="POSITION">%1$d</xliff:g>। चयन गर्नका लागि डबल ट्याप गर्नुहोस्।"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 3cad1fa..41075e3 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> sluiten."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> verwijderd."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle recente apps gesloten."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> starten."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Melding verwijderd."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Startpagina"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recent"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Terug"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Meldingen"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Sneltoetsen"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Invoermethode schakelen"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Apps"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistentie"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contacten"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Chat"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muziek"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Agenda"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Weergeven met volumeknoppen"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Niet storen"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Volumeknoppen als sneltoets"</string>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index 91baa9b..1703a2f 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> ਨੂੰ ਰੱਦ ਕਰੋ।"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ਰੱਦ ਕੀਤਾ।"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ਸਾਰੀਆਂ ਹਾਲੀਆ ਐਪਲੀਕੇਸ਼ਨਾਂ ਰੱਦ ਕੀਤੀਆਂ।"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ਚਾਲੂ ਕਰ ਰਿਹਾ ਹੈ।"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"ਸੂਚਨਾ ਰੱਦ ਕੀਤੀ।"</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ਮੁੱਖ ਸਕ੍ਰੀਨ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ਹਾਲੀਆ"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ਪਿੱਛੇ"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"ਸੂਚਨਾਵਾਂ"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ਵਾਪਸ ਇਨਪੁੱਟ ਵਿਧੀ \'ਤੇ ਬਦਲੋ"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"ਐਪਲੀਕੇਸ਼ਨਾਂ"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"ਸਹਾਇਕ"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ਬ੍ਰਾਊਜ਼ਰ"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"ਸੰਪਰਕ"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ਈਮੇਲ"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"ਸੰਗੀਤ"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"ਕੈਲੰਡਰ"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"ਵੌਲਯੂਮ ਕੰਟਰੋਲਾਂ ਨਾਲ ਵਿਖਾਓ"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ਮੈਨੂੰ ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"ਵੌਲਯੂਮ ਬਟਨ ਸ਼ਾਰਟਕੱਟ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 3aed4b2..297b849 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -170,6 +170,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Usuń stąd <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g>: zamknięto."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Wszystkie ostatnie aplikacje zostały zamknięte."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Uruchamiam <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Zamknięto powiadomienie."</string>
@@ -530,6 +532,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Ekran główny"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Ostatnie"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Wstecz"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Powiadomienia"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Skróty klawiszowe"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Przełącz metodę wprowadzania"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikacje"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Pomoc"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Przeglądarka"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakty"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Komunikator"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muzyka"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendarz"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Pokazuj z regulacją głośności"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Nie przeszkadzać"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Wł./wył. przyciskami głośności"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 055a2981..eb08d99 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Descartar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> descartado."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Todos os apps recentes foram dispensados."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificação dispensada."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Início"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recentes"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Voltar"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notificações"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Atalhos do teclado"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Alterar o método de entrada"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplicativos"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistente"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navegador"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contatos"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Mensagens instantâneas"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Música"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Agenda"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar com controles de volume"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Não perturbe"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Atalho de botões de volume"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index f40c7c7..bba2f3e 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ignorar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ignorado."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Todas as aplicações recentes foram ignoradas."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"A iniciar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificação ignorada."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Página inicial"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recentes"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Anterior"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notificações"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Atalhos de teclado"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Alternar o método de introdução"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplicações"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistência"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navegador"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contactos"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Música"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendário"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar com controlos de volume"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Não incomodar"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Atalho dos botões de volume"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 055a2981..eb08d99 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Descartar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> descartado."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Todos os apps recentes foram dispensados."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificação dispensada."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Início"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recentes"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Voltar"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notificações"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Atalhos do teclado"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Alterar o método de entrada"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplicativos"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistente"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navegador"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contatos"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Mensagens instantâneas"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Música"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Agenda"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar com controles de volume"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Não perturbe"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Atalho de botões de volume"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index a307698..0e818c4 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -169,6 +169,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Închideți <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> a fost eliminată."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Toate aplicațiile recente au fost închise."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Se inițiază <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificarea a fost închisă."</string>
@@ -529,6 +531,30 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Ecran de pornire"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recente"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Înapoi"</string>
+ <!-- no translation found for keyboard_shortcut_group_system_notifications (8366964080041773224) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_system_shortcuts_helper (4892255911160332762) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_system_switch_input (2334164096341310324) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications (9129465955073449206) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_assist (9095441910537146013) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_browser (6465985474000766533) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_contacts (2064197111278436375) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_email (6257036897441939004) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_im (1892749399083161405) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_music (4775559515850922780) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_youtube (6555453761294723317) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_calendar (9043614299194991263) -->
+ <skip />
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Afișează cu comenzile de volum"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Nu deranja"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Comandă rapidă din butoanele de volum"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 5521664..1baa67d 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -170,6 +170,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Удаление приложения <xliff:g id="APP">%s</xliff:g> из списка."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Приложение \"<xliff:g id="APP">%s</xliff:g>\" удалено из списка."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Все недавние приложения закрыты."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Запуск приложения <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Уведомление закрыто"</string>
@@ -514,8 +516,8 @@
<string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
<string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Воспроизведение/пауза"</string>
<string name="keyboard_key_media_stop" msgid="2859963958595908962">"Стоп"</string>
- <string name="keyboard_key_media_next" msgid="1894394911630345607">"Далее"</string>
- <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Назад"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Следующий трек"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Предыдущий трек"</string>
<string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Перемотка назад"</string>
<string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Перемотка вперед"</string>
<string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
@@ -525,11 +527,35 @@
<string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
<string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
<string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
- <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Цифровая клавиатура <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"<xliff:g id="NAME">%1$s</xliff:g> на цифровой панели"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Система"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Главный экран"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Недавние"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
+ <!-- no translation found for keyboard_shortcut_group_system_notifications (8366964080041773224) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_system_shortcuts_helper (4892255911160332762) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_system_switch_input (2334164096341310324) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications (9129465955073449206) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_assist (9095441910537146013) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_browser (6465985474000766533) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_contacts (2064197111278436375) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_email (6257036897441939004) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_im (1892749399083161405) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_music (4775559515850922780) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_youtube (6555453761294723317) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_calendar (9043614299194991263) -->
+ <skip />
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Показывать при нажатии кнопок регулировки громкости"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не беспокоить"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Кнопки регулировки громкости"</string>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index 61411d6..5a2f849 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> ඉවතලන්න."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> අස් කර ඇත."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"සියලුම මෑත යෙඳුම් අස් කරන ලදි."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ආරම්භ කරමින්."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"දැනුම්දීම නිෂ්ප්රභා කරඇත."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"මුල් පිටුව"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"මෑත"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ආපසු"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"දැනුම්දීම්"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"යතුරු පුවරු කෙටිමං"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ආදාන ක්රමය මාරු කිරීම"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"යෙදුම්"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"සහාය"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"බ්රවුසරය"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"සම්බන්ධතා"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ඊ-තැපෑල"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"සංගීතය"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"දින දර්ශනය"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"හඩ පරිමා පාලන සහිතව පෙන්වන්න"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"බාධා නොකරන්න"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"හඩ පරිමා බොත්තම් කෙටිමග"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index f7967e3..9468fcf 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -170,6 +170,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Zrušiť aplikáciu <xliff:g id="APP">%s</xliff:g>"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikácia <xliff:g id="APP">%s</xliff:g> bola zrušená."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Všetky nedávne aplikácie boli odmietnuté."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Spúšťa sa aplikácia <xliff:g id="APP">%s</xliff:g>"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Upozornenie bolo zrušené."</string>
@@ -530,6 +532,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Domovská stránka"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nedávne"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Späť"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Upozornenia"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Klávesové skratky"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Prepnúť metódu vstupu"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikácie"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Pomocná aplikácia"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Prehliadač"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakty"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Okamžité správy"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Hudba"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendár"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Zobrazovať s ovládacími prvkami hlasitosti"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Nerušiť"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Skratka tlačidiel hlasitosti"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index f0b7bc7..c5a43f9 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -170,6 +170,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Opusti aplikacijo <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikacija <xliff:g id="APP">%s</xliff:g> je bila odstranjena."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Vse nedavne aplikacije so bile opuščene."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Zaganjanje aplikacije <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Obvestilo je bilo odstranjeno."</string>
@@ -530,6 +532,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Začetni zaslon"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nedavni"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Nazaj"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Obvestila"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Bližnjične tipke"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Preklop načina vnosa"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikacije"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Pomoč"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Brskalnik"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Stiki"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-pošta"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Neposredno sporočanje"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Glasba"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Koledar"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Prikaži s kontrolniki glasnosti"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne moti"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Bližnjica z gumboma za glasnost"</string>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index 893e471..0188e5b 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Largo <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> është hequr."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Të gjitha aplikacionet e fundit u larguan."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Po nis <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Njoftimi është hequr."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Kreu"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Të fundit"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Prapa"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Njoftimet"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Shkurtoret e tastierës"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Ndërro metodën e hyrjes"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikacionet"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Asistenti"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Shfletuesi"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktet"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Mail-i"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Mesazh i çastit"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muzikë"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendari"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Shfaq me kontrollet e volumit"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Mos shqetëso"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Shkurtorja e butonave të volumit"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 6cfd7b0..501a3e3 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -169,6 +169,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Одбаците <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Апликација <xliff:g id="APP">%s</xliff:g> је одбачена."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Све недавно коришћене апликације су одбачене."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Покрећемо <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Обавештење је одбачено."</string>
@@ -529,6 +531,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Почетни"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Недавни садржај"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Обавештења"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Тастерске пречице"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Промени метод уноса"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Апликације"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Апликација за помоћ"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Прегледач"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Контакти"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Имејл"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Размена тренутних порука"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Музика"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Календар"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Прикажи са контролама јачине звука"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не узнемиравај"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Пречица за дугмад за јачину звука"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 6b1e949..959128e 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ta bort <xliff:g id="APP">%s</xliff:g> från listan."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> togs bort permanent."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alla appar har tagits bort från listan Senaste."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Startar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Meddelandet ignorerades."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Startsida"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Senaste"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Tillbaka"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Aviseringar"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Kortkommandon"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Byt inmatningsmetod"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Appar"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Hjälp"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Webbläsare"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakter"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-post"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Snabbmeddelanden"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musik"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalender"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Visa med volymkontroller"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Stör ej"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Genväg till volymknappar"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 5acf6c0..4b936c9 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ondoa <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> imeondolewa."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Programu za hivi majuzi zimeondolewa."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Inaanzisha <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Arifa imetupwa."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Mwanzo"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Zilizotumika majuzi"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Nyuma"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Arifa"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Mikato ya Kibodi"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Badilisha mbinu ya kuingiza data"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Programu"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Programu ya maagizo ya sauti"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Kivinjari"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Anwani"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Barua pepe"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Ujumbe wa papo kwa papo"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muziki"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalenda"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Onyesha katika vidhibiti vya sauti"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Usinisumbue"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Njia ya mkato ya vitufe vya sauti"</string>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index 1c2f0de..5489be9 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> ஐ நிராகரி."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> விலக்கப்பட்டது."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"எல்லா சமீபத்திய பயன்பாடுகளும் விலக்கப்பட்டன."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ஐத் தொடங்குகிறது."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"அறிவிப்பு நிராகரிக்கப்பட்டது."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"முகப்பு"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"சமீபத்தியவை"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"முந்தையது"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"அறிவிப்புகள்"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"விசைப்பலகைக் குறுக்குவழிகள்"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"உள்ளீட்டு முறையை மாற்று"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"பயன்பாடுகள்"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"அசிஸ்ட்"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"உலாவி"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"தொடர்புகள்"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"மின்னஞ்சல்"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"மியூசிக்"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"கேலெண்டர்"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"ஒலிக் கட்டுப்பாடுகளுடன் காட்டு"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"தொந்தரவு செய்ய வேண்டாம்"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"ஒலியளவுப் பொத்தான்களுக்கான குறுக்குவழி"</string>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index bbefad2..3a72809 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>ని తీసివేయండి."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> తీసివేయబడింది."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"అన్ని ఇటీవలి అనువర్తనాలు తీసివేయబడ్డాయి."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>ని ప్రారంభిస్తోంది."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"నోటిఫికేషన్ తీసివేయబడింది."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"హోమ్"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ఇటీవలివి"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"వెనుకకు"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"నోటిఫికేషన్లు"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"కీబోర్డ్ సత్వరమార్గాలు"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ఇన్పుట్ పద్ధతిని మార్చండి"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"అనువర్తనాలు"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"సహాయకం"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"బ్రౌజర్"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"పరిచయాలు"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ఇమెయిల్"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"సంగీతం"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"క్యాలెండర్"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"వాల్యూమ్ నియంత్రణలతో చూపు"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"అంతరాయం కలిగించవద్దు"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"వాల్యూమ్ బటన్ల సత్వరమార్గం"</string>
@@ -588,8 +602,8 @@
<string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"స్థానం <xliff:g id="POSITION">%1$d</xliff:g>. ఎంచుకోవడానికి రెండుసార్లు నొక్కండి."</string>
<string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g>ని తరలిస్తుంది"</string>
<string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g>ని తీసివేస్తుంది"</string>
- <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> స్థానం <xliff:g id="POSITION">%2$d</xliff:g>కి జోడించబడింది"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g>వ స్థానానికి జోడించబడింది"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> తీసివేయబడింది"</string>
- <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> స్థానం <xliff:g id="POSITION">%2$d</xliff:g>కి తరలించబడింది"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g>వ స్థానానికి తరలించబడింది"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"శీఘ్ర సెట్టింగ్ల ఎడిటర్."</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 809d425..4844c84 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"ยกเลิก <xliff:g id="APP">%s</xliff:g>"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ถูกลบไปแล้ว"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ปิดแอปพลิเคชันล่าสุดทั้งหมดแล้ว"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"กำลังเริ่มต้น <xliff:g id="APP">%s</xliff:g>"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"ปิดการแจ้งเตือนแล้ว"</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"หน้าแรก"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ล่าสุด"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"กลับ"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"การแจ้งเตือน"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"แป้นพิมพ์ลัด"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"สลับวิธีการป้อนข้อมูล"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"แอปพลิเคชัน"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"การสนับสนุน"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"เบราว์เซอร์"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"รายชื่อติดต่อ"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"อีเมล"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"เพลง"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"ปฏิทิน"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"แสดงพร้อมการควบคุมระดับเสียง"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ห้ามรบกวน"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"ทางลัดปุ่มปรับระดับเสียง"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 7e6ff8a..0672959 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"I-dismiss ang <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Hindi pinansin ang <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Na-dismiss ang lahat ng kamakailang application."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Sinisimulan ang <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Na-dismiss ang notification."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Home"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Mga Kamakailang Ginamit"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Bumalik"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Mga Notification"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Mga Keyboard Shortcut"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Magpalit ng pamamaraan ng pag-input"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Mga Application"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Tulong"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Mga Contact"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Music"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendaryo"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Ipakita nang may mga kontrol ng volume"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Huwag istorbohin"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Shortcut ng mga button ng volume"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 05621a5..58d488c 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> uygulamasını kapat."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> kaldırıldı."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Tüm son uygulamalar kapatıldı."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> başlatılıyor."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Bildirim kapatıldı."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Ana ekran"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Son çağrılar"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Geri"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Bildirimler"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Klavye Kısayolları"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Giriş yöntemini değiştir"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Uygulamalar"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Asist"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Tarayıcı"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kişiler"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-posta"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Müzik"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Takvim"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Ses seviyesi kontrolleriyle göster"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Rahatsız etmeyin"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Ses düğmeleri kısayolu"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index ac79649..c75891c 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -170,6 +170,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Видалити додаток <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Програму <xliff:g id="APP">%s</xliff:g> закрито."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Усі останні додатки закрито."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Запуск додатка <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Сповіщення відхилено."</string>
@@ -530,6 +532,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Головний екран"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Останні"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Сповіщення"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Комбінації клавіш"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Змінити метод введення"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Додатки"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Помічник"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Веб-переглядач"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Контакти"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Електронна пошта"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Чат"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Музика"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Календар"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Показувати регулятори гучності"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не турбувати"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Кнопки гучності на корпусі"</string>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index a4a664b..807a923 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> کو مسترد کریں۔"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> کو ہٹا دیا گیا۔"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"سبھی حالیہ ایپلیکیشنز کو برخاست کر دیا گیا۔"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> شروع ہو رہی ہے۔"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"اطلاع مسترد ہوگئی۔"</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ہوم"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"حالیہ"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"پیچھے"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"اطلاعات"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"کی بورڈ شارٹ کٹس"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"اندراج کا طریقہ سوئچ کریں"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"ایپلیکیشنز"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"اسسٹ"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"براؤزر"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"رابطے"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ای میل"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"موسیقی"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"کیلنڈر"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"والیوم کنٹرولز کے ساتھ دکھائیں"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ڈسٹرب نہ کریں"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"والیوم بٹنز کے شارٹ کٹ"</string>
@@ -591,5 +605,5 @@
<string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="POSITION">%2$d</xliff:g> پوزیشن پر <xliff:g id="TILE_NAME">%1$s</xliff:g> شامل ہو گیا ہے"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ہٹا دیا گیا"</string>
<string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="POSITION">%2$d</xliff:g> پوزیشن پر <xliff:g id="TILE_NAME">%1$s</xliff:g> منتقل ہو گیا ہے"</string>
- <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"فوری ترتیبات ایڈیٹر۔"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"فوری ترتیبات کا ایڈیٹر۔"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index f5bcc3d..fe67b52 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Olib tashlash: <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> olib tashlangan."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Yaqinda ishlatilgan barcha ilovalar olib tashlandi."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ishga tushirilmoqda."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Xabarnoma e‘tiborsiz qoldirildi."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Bosh ekran"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"So‘nggi ishlatilganlar"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Orqaga"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Bildirishnomalar"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Tezkor tugmalar"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Matn kiritish usulini o‘zgartirish"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Ilovalar"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Yordamchi"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Brauzer"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktlar"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-pochta"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musiqa"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Taqvim"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Ovoz balandligini boshqarish tugmalari bilan ko‘rsatish"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Bezovta qilinmasin"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Ovoz balandligini boshqarish tugmalari"</string>
@@ -563,7 +577,7 @@
<string name="select_keycode" msgid="7413765103381924584">"Klaviatura tugmasini tanlang"</string>
<string name="preview" msgid="9077832302472282938">"Oldindan ko‘rish"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Fragmentlar qo‘shish uchun torting"</string>
- <string name="drag_to_remove_tiles" msgid="3361212377437088062">"O‘chirish uchun bu yerga sudrang"</string>
+ <string name="drag_to_remove_tiles" msgid="3361212377437088062">"O‘chirish uchun bu yerga torting"</string>
<string name="qs_edit" msgid="2232596095725105230">"Tahrirlash"</string>
<string name="tuner_time" msgid="6572217313285536011">"Vaqt"</string>
<string-array name="clock_options">
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index ed3e8f3..ca7c59b 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Xóa bỏ <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> đã bị loại bỏ."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Đã bỏ qua tất cả các ứng dụng gần đây."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Bắt đầu <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Đã loại bỏ thông báo."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Màn hình chính"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Gần đây"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Quay lại"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Thông báo"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Phím tắt"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Chuyển phương thức nhập"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Ứng dụng"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Trợ lý"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Trình duyệt"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Danh bạ"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Nhắn tin nhanh"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Âm nhạc"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Lịch"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Hiển thị với các điều khiển âm lượng"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Không làm phiền"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Phím tắt các nút âm lượng"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 3b0c023..d559344 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"移除<xliff:g id="APP">%s</xliff:g>。"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"已删除<xliff:g id="APP">%s</xliff:g>"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"已关闭所有最近用过的应用。"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"正在启动<xliff:g id="APP">%s</xliff:g>。"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"已关闭通知。"</string>
@@ -528,6 +530,30 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"主屏幕"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"最近"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"返回"</string>
+ <!-- no translation found for keyboard_shortcut_group_system_notifications (8366964080041773224) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_system_shortcuts_helper (4892255911160332762) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_system_switch_input (2334164096341310324) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications (9129465955073449206) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_assist (9095441910537146013) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_browser (6465985474000766533) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_contacts (2064197111278436375) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_email (6257036897441939004) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_im (1892749399083161405) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_music (4775559515850922780) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_youtube (6555453761294723317) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_calendar (9043614299194991263) -->
+ <skip />
<string name="tuner_full_zen_title" msgid="4540823317772234308">"与音量控件一起显示"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"请勿打扰"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"音量按钮快捷键"</string>
@@ -583,7 +609,7 @@
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"左移"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"右移"</string>
<string name="forced_resizable_info_text" msgid="7591061837558867999">"应用可能无法在多窗口模式下正常运行"</string>
- <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"位置 <xliff:g id="POSITION">%1$d</xliff:g>,<xliff:g id="TILE_NAME">%2$s</xliff:g>。点按再次即可修改。"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"位置 <xliff:g id="POSITION">%1$d</xliff:g>,<xliff:g id="TILE_NAME">%2$s</xliff:g>。点按两次即可修改。"</string>
<string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>。点按两次即可添加。"</string>
<string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"位置 <xliff:g id="POSITION">%1$d</xliff:g>。点按两次即可选择。"</string>
<string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"移动<xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
@@ -591,5 +617,5 @@
<string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"已将<xliff:g id="TILE_NAME">%1$s</xliff:g>添加到位置 <xliff:g id="POSITION">%2$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"已移除<xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"已将<xliff:g id="TILE_NAME">%1$s</xliff:g>移至位置 <xliff:g id="POSITION">%2$d</xliff:g>"</string>
- <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"快速设置编辑器。"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"快捷设置编辑器。"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index dc4a6dd..083cd5e 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"關閉「<xliff:g id="APP">%s</xliff:g>」。"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"「<xliff:g id="APP">%s</xliff:g>」已關閉。"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"所有最近使用的應用程式均已關閉。"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"正在啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g><xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"通知已關閉。"</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"主畫面"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"最近的活動"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"返回"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"通知"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"鍵盤快速鍵"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"切換輸入法"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"應用程式"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"輔助"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"瀏覽器"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"通訊錄"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"電郵"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"即時通訊"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"音樂"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"日曆"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"與音量控制一起顯示"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"請勿騷擾"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"音量按鈕快速鍵"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 72ff27c8b..3c95a93 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"關閉「<xliff:g id="APP">%s</xliff:g>」。"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"「<xliff:g id="APP">%s</xliff:g>」已關閉。"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"最近使用的應用程式已全部關閉。"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"正在啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"已關閉通知。"</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"主畫面"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"近期活動"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"返回"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"通知"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"鍵盤快速鍵"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"切換輸入法"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"應用程式"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"小幫手"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"瀏覽器"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"聯絡人"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"電子郵件"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"即時訊息"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"音樂"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"日曆"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"與音量控制項一起顯示"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"零打擾"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"音量按鈕快速鍵"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 2eb9681..e03e642 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Cashisa i-<xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ivaliwe."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Zonke izinhlelo zokusebenza zakamuva zicashisiwe."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iqala i-<xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Isaziso sichithiwe."</string>
@@ -528,6 +530,18 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Ekhaya"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Okwakamuva"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Emuva"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Izaziso"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Izinqamulelo Zekhibhodi"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Shintsha indlela yokufaka"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Izinhlelo zokusebenza"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Siza"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Isiphequluli"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Oxhumana nabo"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"I-imeyili"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"I-IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Umculo"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"I-YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Ikhalenda"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Bonisa ngezilawuli zevolomu"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ungaphazamisi"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Izinqamuleli zezinkinobho zevolomu"</string>
diff --git a/packages/SystemUI/res/values/dimens_tv.xml b/packages/SystemUI/res/values/dimens_tv.xml
index 953dd65..337513d 100644
--- a/packages/SystemUI/res/values/dimens_tv.xml
+++ b/packages/SystemUI/res/values/dimens_tv.xml
@@ -38,9 +38,6 @@
<dimen name="recents_tv_unselected_item_z">6dp</dimen>
<dimen name="recents_tv_selected_item_z_delta">10dp</dimen>
- <!-- Extra space around the PIP and its outline in PIP onboarding activity -->
- <dimen name="tv_pip_bounds_space">3dp</dimen>
-
<!-- Values for text on recents cards on tv -->
<dimen name="recents_tv_title_text_size">12sp</dimen>
@@ -52,4 +49,10 @@
<dimen name="recents_tv_dismiss_icon_bottom_margin">1dip</dimen>
<dimen name="recents_tv_dismiss_text_size">12sp</dimen>
+ <!-- Values for PIP in recents -->
+ <dimen name="recents_tv_pip_controls_margin_top">10dp</dimen>
+
+ <!-- Extra space around the PIP and its outline in PIP onboarding activity -->
+ <dimen name="tv_pip_bounds_space">3dp</dimen>
+
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index a523a41..060e050 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -417,6 +417,8 @@
<string name="accessibility_recents_item_dismissed"><xliff:g id="app" example="Calendar">%s</xliff:g> dismissed.</string>
<!-- Content description to tell the user all applications has been removed from recents -->
<string name="accessibility_recents_all_items_dismissed">All recent applications dismissed.</string>
+ <!-- Content description to tell the user that this button will open application info for an application in recents -->
+ <string name="accessibility_recents_item_open_app_info">Open <xliff:g id="app" example="Calendar">%s</xliff:g> application info.</string>
<!-- Content description to tell the user an application has been launched from recents -->
<string name="accessibility_recents_item_launched">Starting <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
<!-- Content description of individual recents task. -->
@@ -1388,6 +1390,31 @@
<string name="keyboard_shortcut_group_system_recents">Recents</string>
<!-- User visible title for the the keyboard shortcut that triggers the back action. -->
<string name="keyboard_shortcut_group_system_back">Back</string>
+ <!-- User visible title for the the keyboard shortcut that triggers the notification shade. -->
+ <string name="keyboard_shortcut_group_system_notifications">Notifications</string>
+ <!-- User visible title for the the keyboard shortcut that triggers the keyboard shortcuts helper. -->
+ <string name="keyboard_shortcut_group_system_shortcuts_helper">Keyboard Shortcuts</string>
+ <!-- User visible title for the the keyboard shortcut that switches input methods. -->
+ <string name="keyboard_shortcut_group_system_switch_input">Switch input method</string>
+
+ <!-- User visible title for the system-wide applications keyboard shortcuts list. -->
+ <string name="keyboard_shortcut_group_applications">Applications</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the assist app. -->
+ <string name="keyboard_shortcut_group_applications_assist">Assist</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the browser app. -->
+ <string name="keyboard_shortcut_group_applications_browser">Browser</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the contacts app. -->
+ <string name="keyboard_shortcut_group_applications_contacts">Contacts</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the email app. -->
+ <string name="keyboard_shortcut_group_applications_email">Email</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the instant messaging app. -->
+ <string name="keyboard_shortcut_group_applications_im">IM</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the music app. -->
+ <string name="keyboard_shortcut_group_applications_music">Music</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the YouTube app. -->
+ <string name="keyboard_shortcut_group_applications_youtube">YouTube</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the calendar app. -->
+ <string name="keyboard_shortcut_group_applications_calendar">Calendar</string>
<!-- SysUI Tuner: Option to show full do not disturb panel in volume [CHAR LIMIT=60] -->
<string name="tuner_full_zen_title">Show with volume controls</string>
diff --git a/packages/SystemUI/res/xml/night_mode.xml b/packages/SystemUI/res/xml/night_mode.xml
index d5f5333..34af820 100644
--- a/packages/SystemUI/res/xml/night_mode.xml
+++ b/packages/SystemUI/res/xml/night_mode.xml
@@ -27,10 +27,6 @@
android:title="@string/when_night_mode_on">
<SwitchPreference
- android:key="dark_theme"
- android:title="@string/use_dark_theme" />
-
- <SwitchPreference
android:key="adjust_tint"
android:title="@string/adjust_tint" />
@@ -40,8 +36,4 @@
</PreferenceCategory>
- <Preference
- android:selectable="false"
- android:summary="@string/night_mode_disclaimer" />
-
</PreferenceScreen>
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index aa3f6e5..d12ab29 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -514,7 +514,7 @@
if (canBeExpanded) {
if (DEBUG) Log.d(TAG, "working on an expandable child");
mNaturalHeight = mScaler.getNaturalHeight();
- mSmallSize = v.getMinExpandHeight();
+ mSmallSize = v.getCollapsedHeight();
} else {
if (DEBUG) Log.d(TAG, "working on a non-expandable child");
mNaturalHeight = mOldHeight;
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 8f79bda..c0a565db 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -325,10 +325,11 @@
/**
* @param view The view to be dismissed
* @param velocity The desired pixels/second speed at which the view should move
+ * @param useAccelerateInterpolator Should an accelerating Interpolator be used
*/
- public void dismissChild(final View view, float velocity) {
+ public void dismissChild(final View view, float velocity, boolean useAccelerateInterpolator) {
dismissChild(view, velocity, null /* endAction */, 0 /* delay */,
- velocity == 0 /* useAccelerateInterpolator */, 0 /* fixedDuration */);
+ useAccelerateInterpolator, 0 /* fixedDuration */);
}
/**
@@ -569,7 +570,8 @@
if (!handleUpEvent(ev, mCurrView, velocity, getTranslation(mCurrView))) {
if (isDismissGesture(ev)) {
// flingadingy
- dismissChild(mCurrView, swipedFastEnough() ? velocity : 0f);
+ dismissChild(mCurrView, velocity,
+ !swipedFastEnough() /* useAccelerateInterpolator */);
} else {
// snappity
mCallback.onDragCancelled(mCurrView);
@@ -615,11 +617,9 @@
protected boolean swipedFastEnough() {
float velocity = getVelocity(mVelocityTracker);
- float perpendicularVelocity = getPerpendicularVelocity(mVelocityTracker);
float translation = getTranslation(mCurrView);
- boolean ret = (Math.abs(velocity) > getEscapeVelocity()) &&
- (Math.abs(velocity) > Math.abs(perpendicularVelocity)) &&
- (velocity > 0) == (translation > 0);
+ boolean ret = (Math.abs(velocity) > getEscapeVelocity())
+ && (velocity > 0) == (translation > 0);
return ret;
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 0d75fdd..53c2233 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -27,9 +27,25 @@
import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.phone.QSTileHost;
import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarWindowManager;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.FlashlightController;
+import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NextAlarmController;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.SecurityController;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.policy.ZenModeController;
/**
* Class factory to provide customizable SystemUI components.
@@ -82,6 +98,20 @@
return new NotificationIconAreaController(context, phoneStatusBar);
}
+ public QSTileHost createQSTileHost(Context context, PhoneStatusBar statusBar,
+ BluetoothController bluetooth, LocationController location,
+ RotationLockController rotation, NetworkController network,
+ ZenModeController zen, HotspotController hotspot,
+ CastController cast, FlashlightController flashlight,
+ UserSwitcherController userSwitcher, UserInfoController userInfo,
+ KeyguardMonitor keyguard, SecurityController security,
+ BatteryController battery, StatusBarIconController iconController,
+ NextAlarmController nextAlarmController) {
+ return new QSTileHost(context, statusBar, bluetooth, location, rotation, network, zen,
+ hotspot, cast, flashlight, userSwitcher, userInfo, keyguard, security, battery,
+ iconController, nextAlarmController);
+ }
+
public <T> T createInstance(Class<T> classType) {
return null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 58d7c81..de8eec4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -118,7 +118,7 @@
} else if (MOVE_FULL_ROWS.equals(key)) {
mFullRows = newValue == null || Integer.parseInt(newValue) != 0;
} else if (QuickQSPanel.NUM_QUICK_TILES.equals(key)) {
- mNumQuickTiles = QuickQSPanel.getNumQuickTiles(mQsContainer.getContext());
+ mNumQuickTiles = mQuickQsPanel.getNumQuickTiles(mQsContainer.getContext());
clearAnimationState();
}
updateAnimators();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 98a1c23..57a1a4a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -37,7 +37,7 @@
private final int mTileSpacingPx;
private int mTilePaddingTopPx;
- private TextView mLabel;
+ protected TextView mLabel;
private ImageView mPadLock;
public QSTileView(Context context, QSIconView icon) {
@@ -81,7 +81,7 @@
FontSizeUtils.updateFontSize(mLabel, R.dimen.qs_tile_text_size);
}
- private void createLabel() {
+ protected void createLabel() {
final Resources res = mContext.getResources();
View view = LayoutInflater.from(mContext).inflate(R.layout.qs_tile_label, null);
mLabel = (TextView) view.findViewById(R.id.tile_label);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index ab90179..2ef3672 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -143,7 +143,7 @@
}
};
- public static int getNumQuickTiles(Context context) {
+ public int getNumQuickTiles(Context context) {
return TunerService.get(context).getValue(NUM_QUICK_TILES, 5);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
new file mode 100644
index 0000000..e512f93
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 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.systemui.qs.customize;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
+import com.android.systemui.R;
+import com.android.systemui.qs.QSIconView;
+import com.android.systemui.qs.QSTileView;
+import libcore.util.Objects;
+
+public class CustomizeTileView extends QSTileView {
+
+ private TextView mAppLabel;
+
+ public CustomizeTileView(Context context, QSIconView icon) {
+ super(context, icon);
+ }
+
+ @Override
+ protected void createLabel() {
+ super.createLabel();
+ View view = LayoutInflater.from(mContext).inflate(R.layout.qs_tile_label, null);
+ mAppLabel = (TextView) view.findViewById(R.id.tile_label);
+ mAppLabel.setAlpha(.6f);
+ mAppLabel.setSingleLine(true);
+ addView(view);
+ }
+
+ public void setShowAppLabel(boolean showAppLabel) {
+ mAppLabel.setVisibility(showAppLabel ? View.VISIBLE : View.GONE);
+ mLabel.setSingleLine(showAppLabel);
+ }
+
+ public void setAppLabel(CharSequence label) {
+ if (!Objects.equal(label, mAppLabel.getText())) {
+ mAppLabel.setText(label);
+ }
+ }
+
+ public TextView getAppLabel() {
+ return mAppLabel;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 83ac45c..716185f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -125,6 +125,7 @@
mClipper.animateCircularClip(x, y, true, mExpandAnimationListener);
new TileQueryHelper(mContext, mHost).setListener(mTileAdapter);
mNotifQsContainer.setCustomizerAnimating(true);
+ mNotifQsContainer.setCustomizerShowing(true);
}
}
@@ -137,6 +138,7 @@
save();
mClipper.animateCircularClip(x, y, false, mCollapseAnimationListener);
mNotifQsContainer.setCustomizerAnimating(true);
+ mNotifQsContainer.setCustomizerShowing(false);
}
}
@@ -175,6 +177,7 @@
specs.add(tile.getTileSpec());
}
mTileAdapter.setTileSpecs(specs);
+ mRecyclerView.setAdapter(mTileAdapter);
}
private void save() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 4c13451..2ba4044 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -41,7 +41,6 @@
import com.android.internal.logging.MetricsProto;
import com.android.systemui.R;
import com.android.systemui.qs.QSIconView;
-import com.android.systemui.qs.QSTileView;
import com.android.systemui.qs.customize.TileAdapter.Holder;
import com.android.systemui.qs.customize.TileQueryHelper.TileInfo;
import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener;
@@ -61,6 +60,10 @@
private static final int TYPE_TILE = 0;
private static final int TYPE_EDIT = 1;
private static final int TYPE_ACCESSIBLE_DROP = 2;
+ private static final int TYPE_DIVIDER = 4;
+
+ private static final long EDIT_ID = 10000;
+ private static final long DIVIDER_ID = 20000;
private final Context mContext;
@@ -68,7 +71,8 @@
private final List<TileInfo> mTiles = new ArrayList<>();
private final ItemTouchHelper mItemTouchHelper;
private final AccessibilityManager mAccessibilityManager;
- private int mDividerIndex;
+ private int mEditIndex;
+ private int mTileDividerIndex;
private boolean mNeedsFocus;
private List<String> mCurrentSpecs;
private List<TileInfo> mOtherTiles;
@@ -87,7 +91,8 @@
@Override
public long getItemId(int position) {
- return mTiles.get(position) != null ? mAllTiles.indexOf(mTiles.get(position)) : -1;
+ return mTiles.get(position) != null ? mAllTiles.indexOf(mTiles.get(position))
+ : position == mEditIndex ? EDIT_ID : DIVIDER_ID;
}
public ItemTouchHelper getItemTouchHelper() {
@@ -131,8 +136,19 @@
}
}
mTiles.add(null);
+ for (int i = 0; i < mOtherTiles.size(); i++) {
+ final TileInfo tile = mOtherTiles.get(i);
+ if (tile.isSystem) {
+ mOtherTiles.remove(i--);
+ mTiles.add(tile);
+ }
+ }
+ if (mOtherTiles.size() != 0) {
+ mTileDividerIndex = mTiles.size();
+ mTiles.add(null);
+ }
mTiles.addAll(mOtherTiles);
- mDividerIndex = mTiles.indexOf(null);
+ mEditIndex = mTiles.indexOf(null);
notifyDataSetChanged();
}
@@ -147,9 +163,12 @@
@Override
public int getItemViewType(int position) {
- if (mAccessibilityMoving && position == mDividerIndex - 1) {
+ if (mAccessibilityMoving && position == mEditIndex - 1) {
return TYPE_ACCESSIBLE_DROP;
}
+ if (position == mTileDividerIndex) {
+ return TYPE_DIVIDER;
+ }
if (mTiles.get(position) == null) {
return TYPE_EDIT;
}
@@ -160,12 +179,15 @@
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
final Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
+ if (viewType == TYPE_DIVIDER) {
+ return new Holder(inflater.inflate(R.layout.qs_customize_tile_divider, parent, false));
+ }
if (viewType == TYPE_EDIT) {
return new Holder(inflater.inflate(R.layout.qs_customize_divider, parent, false));
}
FrameLayout frame = (FrameLayout) inflater.inflate(R.layout.qs_customize_tile_frame, parent,
false);
- frame.addView(new QSTileView(context, new QSIconView(context)));
+ frame.addView(new CustomizeTileView(context, new QSIconView(context)));
return new Holder(frame);
}
@@ -176,6 +198,9 @@
@Override
public void onBindViewHolder(final Holder holder, final int position) {
+ if (holder.getItemViewType() == TYPE_DIVIDER) {
+ return;
+ }
if (holder.getItemViewType() == TYPE_EDIT) {
((TextView) holder.itemView.findViewById(android.R.id.title)).setText(
mCurrentDrag != null ? R.string.drag_to_remove_tiles
@@ -213,7 +238,7 @@
TileInfo info = mTiles.get(position);
- if (position > mDividerIndex) {
+ if (position > mEditIndex) {
info.state.contentDescription = mContext.getString(
R.string.accessibility_qs_edit_add_tile_label, info.state.label);
} else if (mAccessibilityMoving) {
@@ -224,9 +249,11 @@
R.string.accessibility_qs_edit_tile_label, position + 1, info.state.label);
}
holder.mTileView.onStateChanged(info.state);
+ holder.mTileView.setAppLabel(info.appLabel);
+ holder.mTileView.setShowAppLabel(position > mTileDividerIndex);
if (mAccessibilityManager.isTouchExplorationEnabled()) {
- final boolean selectable = !mAccessibilityMoving || position < mDividerIndex;
+ final boolean selectable = !mAccessibilityMoving || position < mEditIndex;
holder.mTileView.setClickable(selectable);
holder.mTileView.setFocusable(selectable);
holder.mTileView.setImportantForAccessibility(selectable
@@ -239,7 +266,7 @@
if (mAccessibilityMoving) {
selectPosition(position, v);
} else {
- if (position < mDividerIndex) {
+ if (position < mEditIndex) {
showAccessibilityDialog(position, v);
} else {
startAccessibleDrag(position);
@@ -253,7 +280,7 @@
private void selectPosition(int position, View v) {
// Remove the placeholder.
- mTiles.remove(mDividerIndex--);
+ mTiles.remove(mEditIndex--);
mAccessibilityMoving = false;
move(mAccessibilityFromIndex, position, v);
notifyDataSetChanged();
@@ -272,7 +299,7 @@
if (which == 0) {
startAccessibleDrag(position);
} else {
- move(position, mDividerIndex, v);
+ move(position, mEditIndex, v);
}
}
}).setNegativeButton(android.R.string.cancel, null)
@@ -287,7 +314,7 @@
mNeedsFocus = true;
mAccessibilityFromIndex = position;
// Add placeholder for last slot.
- mTiles.add(mDividerIndex++, null);
+ mTiles.add(mEditIndex++, null);
notifyDataSetChanged();
}
@@ -296,25 +323,38 @@
}
private boolean move(int from, int to, View v) {
- if (to > mDividerIndex) {
- if (from >= mDividerIndex) {
+ if (to >= mEditIndex) {
+ if (from >= mEditIndex) {
return false;
}
+ // Sort tiles into system/non-system groups.
+ TileInfo tile = mTiles.get(from);
+ if (tile.isSystem) {
+ if (to > mTileDividerIndex) {
+ to = mTileDividerIndex;
+ }
+ } else {
+ if (mTileDividerIndex == mTiles.size()) {
+ mTiles.add(null);
+ }
+ if (to <= mTileDividerIndex) {
+ to = mTileDividerIndex;
+ }
+ }
}
CharSequence fromLabel = mTiles.get(from).state.label;
move(from, to, mTiles);
- mDividerIndex = mTiles.indexOf(null);
- notifyItemChanged(from);
- notifyItemMoved(from, to);
+ notifyDataSetChanged();
+ updateDividerLocations();
CharSequence announcement;
- if (to >= mDividerIndex) {
+ if (to >= mEditIndex) {
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_REMOVE_SPEC,
strip(mTiles.get(to)));
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_REMOVE,
from);
announcement = mContext.getString(R.string.accessibility_qs_edit_tile_removed,
fromLabel);
- } else if (from >= mDividerIndex) {
+ } else if (from >= mEditIndex) {
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_ADD_SPEC,
strip(mTiles.get(to)));
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_ADD,
@@ -333,6 +373,25 @@
return true;
}
+ private void updateDividerLocations() {
+ // The first null is the edit tiles label, the second null is the tile divider.
+ // If there is no second null, then there are no non-system tiles.
+ mEditIndex = -1;
+ mTileDividerIndex = mTiles.size();
+ for (int i = 0; i < mTiles.size(); i++) {
+ if (mTiles.get(i) == null) {
+ if (mEditIndex == -1) {
+ mEditIndex = i;
+ } else {
+ mTileDividerIndex = i;
+ }
+ }
+ }
+ if (mTiles.get(mTiles.size() - 1) == null) {
+ mTiles.remove(mTiles.size() - 1);
+ }
+ }
+
private String strip(TileInfo tileInfo) {
String spec = tileInfo.spec;
if (spec.startsWith(CustomTile.PREFIX)) {
@@ -348,12 +407,12 @@
}
public class Holder extends ViewHolder {
- private QSTileView mTileView;
+ private CustomizeTileView mTileView;
public Holder(View itemView) {
super(itemView);
if (itemView instanceof FrameLayout) {
- mTileView = (QSTileView) ((FrameLayout) itemView).getChildAt(0);
+ mTileView = (CustomizeTileView) ((FrameLayout) itemView).getChildAt(0);
mTileView.setBackground(null);
mTileView.getIcon().disableAnimation();
}
@@ -367,6 +426,9 @@
mTileView.findViewById(R.id.tile_label).animate()
.setDuration(DRAG_LENGTH)
.alpha(0);
+ mTileView.getAppLabel().animate()
+ .setDuration(DRAG_LENGTH)
+ .alpha(0);
}
public void stopDrag() {
@@ -377,13 +439,17 @@
mTileView.findViewById(R.id.tile_label).animate()
.setDuration(DRAG_LENGTH)
.alpha(1);
+ mTileView.getAppLabel().animate()
+ .setDuration(DRAG_LENGTH)
+ .alpha(.6f);
}
}
private final SpanSizeLookup mSizeLookup = new SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
- return getItemViewType(position) == TYPE_EDIT ? 3 : 1;
+ final int type = getItemViewType(position);
+ return type == TYPE_EDIT || type == TYPE_DIVIDER ? 3 : 1;
}
};
@@ -401,7 +467,7 @@
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final ViewHolder holder = parent.getChildViewHolder(child);
- if (holder.getAdapterPosition() < mDividerIndex) {
+ if (holder.getAdapterPosition() < mEditIndex) {
continue;
}
@@ -443,7 +509,7 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- notifyItemChanged(mDividerIndex);
+ notifyItemChanged(mEditIndex);
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index bbc8856..d04a2fc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -31,6 +31,7 @@
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.QSTile.DrawableIcon;
+import com.android.systemui.qs.QSTile.State;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.statusbar.phone.QSTileHost;
@@ -79,7 +80,7 @@
mainHandler.post(new Runnable() {
@Override
public void run() {
- addTile(spec, state);
+ addTile(spec, null, state, true);
mListener.onTilesChanged(mTiles);
}
});
@@ -103,28 +104,33 @@
mListener = listener;
}
- private void addTile(String spec, QSTile.State state) {
+ private void addTile(String spec, CharSequence appLabel, State state, boolean isSystem) {
if (mSpecs.contains(spec)) {
return;
}
TileInfo info = new TileInfo();
info.state = state;
info.spec = spec;
+ info.appLabel = appLabel;
+ info.isSystem = isSystem;
mTiles.add(info);
mSpecs.add(spec);
}
- private void addTile(String spec, Drawable drawable, CharSequence label, Context context) {
+ private void addTile(String spec, Drawable drawable, CharSequence label, CharSequence appLabel,
+ Context context) {
QSTile.State state = new QSTile.State();
state.label = label;
state.contentDescription = label;
state.icon = new DrawableIcon(drawable);
- addTile(spec, state);
+ addTile(spec, appLabel, state, false);
}
public static class TileInfo {
public String spec;
+ public CharSequence appLabel;
public QSTile.State state;
+ public boolean isSystem;
}
private class QueryTilesTask extends AsyncTask<Void, Void, Collection<TileInfo>> {
@@ -147,7 +153,8 @@
icon.setTint(mContext.getColor(android.R.color.white));
}
CharSequence label = info.serviceInfo.loadLabel(pm);
- addTile(spec, icon, label != null ? label.toString() : "null", mContext);
+ final CharSequence appLabel = info.serviceInfo.applicationInfo.loadLabel(pm);
+ addTile(spec, icon, label != null ? label.toString() : "null", appLabel, mContext);
}
return tiles;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
index 6ddd46e..2032783 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -21,6 +21,7 @@
import android.content.IntentFilter;
import android.graphics.drawable.Drawable;
import android.os.Handler;
+import android.os.Looper;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.RelativeSizeSpan;
@@ -44,7 +45,6 @@
public class BatteryTile extends QSTile<QSTile.State> implements BatteryController.BatteryStateChangeCallback {
- private final BatteryMeterDrawable mDrawable;
private final BatteryController mBatteryController;
private final BatteryDetail mBatteryDetail = new BatteryDetail();
@@ -52,13 +52,11 @@
private boolean mPowerSave;
private boolean mCharging;
private boolean mDetailShown;
+ private boolean mPluggedIn;
public BatteryTile(Host host) {
super(host);
mBatteryController = host.getBatteryController();
- mDrawable = new BatteryMeterDrawable(host.getContext(), new Handler(),
- host.getContext().getColor(R.color.batterymeter_frame_color));
- mDrawable.setBatteryController(mBatteryController);
}
@Override
@@ -79,10 +77,8 @@
@Override
public void setListening(boolean listening) {
if (listening) {
- mDrawable.startListening();
mBatteryController.addStateChangedCallback(this);
} else {
- mDrawable.stopListening();
mBatteryController.removeStateChangedCallback(this);
}
}
@@ -118,7 +114,12 @@
state.icon = new Icon() {
@Override
public Drawable getDrawable(Context context) {
- return mDrawable;
+ BatteryMeterDrawable drawable =
+ new BatteryMeterDrawable(context, new Handler(Looper.getMainLooper()),
+ context.getColor(R.color.batterymeter_frame_color));
+ drawable.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
+ drawable.onPowerSaveChanged(mPowerSave);
+ return drawable;
}
@Override
@@ -133,6 +134,7 @@
@Override
public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
mLevel = level;
+ mPluggedIn = pluggedIn;
mCharging = charging;
refreshState((Integer) level);
if (mDetailShown) {
@@ -143,6 +145,7 @@
@Override
public void onPowerSaveChanged(boolean isPowerSave) {
mPowerSave = isPowerSave;
+ refreshState(null);
if (mDetailShown) {
mBatteryDetail.postBindView();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 65154f2..c72bbf3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -154,7 +154,7 @@
state.label = removeDoubleQuotes(cb.enabledDesc);
signalContentDescription = cb.wifiSignalContentDescription;
} else if (wifiNotConnected) {
- state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_full_0);
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_disconnected);
state.label = r.getString(R.string.quick_settings_wifi_label);
signalContentDescription = r.getString(R.string.accessibility_no_wifi);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index fff7d78..8060e07 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -344,7 +344,7 @@
// Update the nav bar scrim, but defer the animation until the enter-window event
boolean animateNavBarScrim = !launchState.launchedViaDockGesture;
- updateNavBarScrim(animateNavBarScrim, null);
+ mScrimViews.updateNavBarScrim(animateNavBarScrim, stack.getTaskCount() > 0, null);
// If this is a new instance relaunched by AM, without going through the normal mechanisms,
// then we have to manually trigger the enter animation state
@@ -417,39 +417,43 @@
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- // Update the nav bar for the current orientation
- updateNavBarScrim(false /* animateNavBarScrim */, AnimationProps.IMMEDIATE);
// Notify of the config change
int newOrientation = getResources().getConfiguration().orientation;
+ int numStackTasks = mRecentsView.getStack().getStackTaskCount();
EventBus.getDefault().send(new ConfigurationChangedEvent(false /* fromMultiWindow */,
- (mLastOrientation != newOrientation)));
+ (mLastOrientation != newOrientation), numStackTasks > 0));
mLastOrientation = newOrientation;
}
@Override
public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
super.onMultiWindowModeChanged(isInMultiWindowMode);
+
+ // Reload the task stack completely
+ RecentsConfiguration config = Recents.getConfiguration();
+ RecentsActivityLaunchState launchState = config.getLaunchState();
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+ RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
+ loader.preloadTasks(loadPlan, -1 /* topTaskId */, false /* isTopTaskHome */);
+
+ RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
+ loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
+ loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
+ loader.loadTasks(this, loadPlan, loadOpts);
+
+ TaskStack stack = loadPlan.getTaskStack();
+ int numStackTasks = stack.getStackTaskCount();
+
EventBus.getDefault().send(new ConfigurationChangedEvent(true /* fromMultiWindow */,
- false /* fromOrientationChange */));
+ false /* fromOrientationChange */, numStackTasks > 0));
if (mRecentsView != null) {
- // Reload the task stack completely
- RecentsConfiguration config = Recents.getConfiguration();
- RecentsActivityLaunchState launchState = config.getLaunchState();
- RecentsTaskLoader loader = Recents.getTaskLoader();
- RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
- loader.preloadTasks(loadPlan, -1 /* topTaskId */, false /* isTopTaskHome */);
-
- RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
- loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
- loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
- loader.loadTasks(this, loadPlan, loadOpts);
-
- mRecentsView.updateStack(loadPlan.getTaskStack());
+ mRecentsView.updateStack(stack);
}
- EventBus.getDefault().send(new MultiWindowStateChangedEvent(isInMultiWindowMode));
+ EventBus.getDefault().send(new MultiWindowStateChangedEvent(isInMultiWindowMode,
+ numStackTasks > 0));
}
@Override
@@ -729,18 +733,4 @@
});
return true;
}
-
- /**
- * Updates the nav bar scrim.
- */
- private void updateNavBarScrim(boolean animateNavBarScrim, AnimationProps animation) {
- // Animate the SystemUI scrims into view
- SystemServicesProxy ssp = Recents.getSystemServices();
- int taskCount = mRecentsView.getStack().getTaskCount();
- boolean hasNavBarScrim = (taskCount > 0) && !ssp.hasTransposedNavBar();
- mScrimViews.prepareEnterRecentsAnimation(hasNavBarScrim, animateNavBarScrim);
- if (animateNavBarScrim && animation != null) {
- mScrimViews.animateNavBarScrimVisibility(true, animation);
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 43d627d..4dae746 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -584,18 +584,24 @@
Rect systemInsets = new Rect();
ssp.getStableInsets(systemInsets);
Rect windowRect = ssp.getWindowRect();
+ // When docked, the nav bar insets are consumed and the activity is measured without insets.
+ // However, the window bounds include the insets, so we need to subtract them here to make
+ // them identical.
+ if (ssp.hasDockedTask()) {
+ windowRect.bottom -= systemInsets.bottom;
+ systemInsets.bottom = 0;
+ }
calculateWindowStableInsets(systemInsets, windowRect);
windowRect.offsetTo(0, 0);
TaskStackLayoutAlgorithm stackLayout = mDummyStackView.getStackAlgorithm();
- stackLayout.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right,
- mTaskStackBounds);
// Rebind the header bar and draw it for the transition
- Rect taskStackBounds = new Rect(mTaskStackBounds);
stackLayout.setSystemInsets(systemInsets);
if (stack != null) {
- stackLayout.initialize(windowRect, taskStackBounds,
+ stackLayout.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right,
+ mTaskStackBounds);
+ stackLayout.initialize(windowRect, mTaskStackBounds,
TaskStackLayoutAlgorithm.StackState.getStackStateForStack(stack));
mDummyStackView.setTasks(stack, false /* allowNotifyStackChanges */);
}
@@ -794,6 +800,9 @@
synchronized (mHeaderBarLock) {
int toHeaderWidth = (int) toTransform.rect.width();
int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale);
+ if (toHeaderWidth <= 0 || toHeaderHeight <= 0) {
+ return null;
+ }
boolean disabledInSafeMode = !toTask.isSystemApp && ssp.isInSafeMode();
mHeaderBar.onTaskViewSizeChanged((int) toTransform.rect.width(),
(int) toTransform.rect.height());
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
index 8be9ca7..e3bc2a7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
@@ -25,9 +25,12 @@
public final boolean fromMultiWindow;
public final boolean fromOrientationChange;
+ public final boolean hasStackTasks;
- public ConfigurationChangedEvent(boolean fromMultiWindow, boolean fromOrientationChange) {
+ public ConfigurationChangedEvent(boolean fromMultiWindow, boolean fromOrientationChange,
+ boolean hasStackTasks) {
this.fromMultiWindow = fromMultiWindow;
this.fromOrientationChange = fromOrientationChange;
+ this.hasStackTasks = hasStackTasks;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
index 19245d9..cf2a68e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
@@ -24,8 +24,10 @@
public class MultiWindowStateChangedEvent extends EventBus.Event {
public final boolean inMultiWindow;
+ public final boolean hasStackTasks;
- public MultiWindowStateChangedEvent(boolean inMultiWindow) {
+ public MultiWindowStateChangedEvent(boolean inMultiWindow, boolean hasStackTasks) {
this.inMultiWindow = inMultiWindow;
+ this.hasStackTasks = hasStackTasks;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java
index b85ddac..216be61 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java
@@ -23,7 +23,7 @@
/**
* This event is sent when a user drags in/out of a drop target.
*/
-public class DragDropTargetChangedEvent extends EventBus.Event {
+public class DragDropTargetChangedEvent extends EventBus.AnimatedEvent {
// The task that is currently being dragged
public final Task task;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 76ca6ca..7aeff1f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -132,6 +132,8 @@
SparseIntArray affiliatedTaskCounts = new SparseIntArray();
String dismissDescFormat = mContext.getString(
R.string.accessibility_recents_item_will_be_dismissed);
+ String appInfoDescFormat = mContext.getString(
+ R.string.accessibility_recents_item_open_app_info);
long lastStackActiveTime = Prefs.getLong(mContext,
Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, 0);
if (RecentsDebugFlags.Static.EnableMockTasks) {
@@ -188,8 +190,9 @@
// Load the title, icon, and color
ActivityInfo info = loader.getAndUpdateActivityInfo(taskKey);
String title = loader.getAndUpdateActivityTitle(taskKey, t.taskDescription);
- String contentDescription = loader.getAndUpdateContentDescription(taskKey, res);
- String dismissDescription = String.format(dismissDescFormat, contentDescription);
+ String titleDescription = loader.getAndUpdateContentDescription(taskKey, res);
+ String dismissDescription = String.format(dismissDescFormat, titleDescription);
+ String appInfoDescription = String.format(appInfoDescFormat, titleDescription);
Drawable icon = isStackTask
? loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, res, false)
: null;
@@ -201,9 +204,9 @@
// Add the task to the stack
Task task = new Task(taskKey, t.affiliatedTaskId, t.affiliatedTaskColor, icon,
- thumbnail, title, contentDescription, dismissDescription, activityColor,
- backgroundColor, isLaunchTarget, isStackTask, isSystemApp, t.isDockable,
- t.bounds, t.taskDescription);
+ thumbnail, title, titleDescription, dismissDescription, appInfoDescription,
+ activityColor, backgroundColor, isLaunchTarget, isStackTask, isSystemApp,
+ t.isDockable, t.bounds, t.taskDescription);
allTasks.add(task);
affiliatedTaskCounts.put(taskKey.id, affiliatedTaskCounts.get(taskKey.id, 0) + 1);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index d5d5aa0..6668079 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -134,10 +134,12 @@
@ViewDebug.ExportedProperty(category="recents")
public String title;
@ViewDebug.ExportedProperty(category="recents")
- public String contentDescription;
+ public String titleDescription;
@ViewDebug.ExportedProperty(category="recents")
public String dismissDescription;
@ViewDebug.ExportedProperty(category="recents")
+ public String appInfoDescription;
+ @ViewDebug.ExportedProperty(category="recents")
public int colorPrimary;
@ViewDebug.ExportedProperty(category="recents")
public int colorBackground;
@@ -174,8 +176,8 @@
}
public Task(TaskKey key, int affiliationTaskId, int affiliationColor, Drawable icon,
- Bitmap thumbnail, String title, String contentDescription,
- String dismissDescription, int colorPrimary, int colorBackground,
+ Bitmap thumbnail, String title, String titleDescription, String dismissDescription,
+ String appInfoDescription, int colorPrimary, int colorBackground,
boolean isLaunchTarget, boolean isStackTask, boolean isSystemApp,
boolean isDockable, Rect bounds, ActivityManager.TaskDescription taskDescription) {
boolean isInAffiliationGroup = (affiliationTaskId != key.id);
@@ -186,8 +188,9 @@
this.icon = icon;
this.thumbnail = thumbnail;
this.title = title;
- this.contentDescription = contentDescription;
+ this.titleDescription = titleDescription;
this.dismissDescription = dismissDescription;
+ this.appInfoDescription = appInfoDescription;
this.colorPrimary = hasAffiliationGroupColor ? affiliationColor : colorPrimary;
this.colorBackground = colorBackground;
this.useLightOnPrimaryColor = Utilities.computeContrastBetweenColors(this.colorPrimary,
@@ -211,8 +214,9 @@
this.icon = o.icon;
this.thumbnail = o.thumbnail;
this.title = o.title;
- this.contentDescription = o.contentDescription;
+ this.titleDescription = o.titleDescription;
this.dismissDescription = o.dismissDescription;
+ this.appInfoDescription = o.appInfoDescription;
this.colorPrimary = o.colorPrimary;
this.colorBackground = o.colorBackground;
this.useLightOnPrimaryColor = o.useLightOnPrimaryColor;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
index 134b90c..483f9e5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -15,8 +15,6 @@
*/
package com.android.systemui.recents.tv;
-import android.animation.AnimatorInflater;
-import android.animation.AnimatorSet;
import android.app.Activity;
import android.app.ActivityOptions;
import android.content.Intent;
@@ -55,11 +53,12 @@
import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.tv.animations.FocusAnimationHolder;
import com.android.systemui.recents.tv.views.RecentsTvView;
import com.android.systemui.recents.tv.views.TaskStackHorizontalViewAdapter;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.tv.pip.PipManager;
-import com.android.systemui.tv.pip.PipControlsView;
+import com.android.systemui.tv.pip.PipRecentsOverlayManager;
import java.util.ArrayList;
import java.util.Collections;
@@ -80,15 +79,13 @@
private boolean mIgnoreAltTabRelease;
private RecentsTvView mRecentsView;
- private PipControlsView mPipControlsView;
- private View mPipShadeView;
- private AnimatorSet mPipControlsViewFadeInAnimator;
- private AnimatorSet mPipControlsViewFadeOutAnimator;
+ private FocusAnimationHolder mRecentsFocusAnimationHolder;
+ private View mPipView;
private TaskStackHorizontalViewAdapter mTaskStackViewAdapter;
private FinishRecentsRunnable mFinishLaunchHomeRunnable;
- private PipManager mPipManager;
- private PipManager.Listener mPipListener = new PipManager.Listener() {
+ private final PipManager mPipManager = PipManager.getInstance();
+ private final PipManager.Listener mPipListener = new PipManager.Listener() {
@Override
public void onPipEntered() {
updatePipUI();
@@ -113,10 +110,38 @@
@Override
public void onPipResizeAboutToStart() { }
-
- @Override
- public void onMediaControllerChanged() { }
};
+ private PipRecentsOverlayManager mPipRecentsOverlayManager;
+ private final PipRecentsOverlayManager.Callback mPipRecentsOverlayManagerCallback =
+ new PipRecentsOverlayManager.Callback() {
+ @Override
+ public void onClosed() {
+ dismissRecentsToLaunchTargetTaskOrHome();
+ }
+
+ @Override
+ public void onBackPressed() {
+ RecentsTvActivity.this.onBackPressed();
+ }
+
+ @Override
+ public void onRecentsFocused() {
+ mRecentsView.requestFocus();
+ }
+ };
+ private final View.OnFocusChangeListener mPipViewFocusChangeListener =
+ new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (hasFocus) {
+ mRecentsFocusAnimationHolder.startFocusLoseAnimation();
+ mPipRecentsOverlayManager.requestFocus(
+ mTaskStackViewAdapter.getItemCount() > 0);
+ } else {
+ mRecentsFocusAnimationHolder.startFocusGainAnimation();
+ }
+ }
+ };
/**
* A common Runnable to finish Recents by launching Home with an animation depending on the
@@ -248,7 +273,7 @@
finish();
return;
}
- mPipManager = PipManager.getInstance();
+ mPipRecentsOverlayManager = PipManager.getInstance().getPipRecentsOverlayManager();
// Register this activity with the event bus
EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
@@ -263,21 +288,19 @@
mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
- mPipControlsView = (PipControlsView) findViewById(R.id.pip_controls);
- mPipControlsView.setListener(new PipControlsView.Listener() {
- @Override
- public void onClosed() {
- dismissRecentsToLaunchTargetTaskOrHome();
- }
- });
- mPipShadeView = findViewById(R.id.pip_shade);
+ mRecentsFocusAnimationHolder = new FocusAnimationHolder(mRecentsView);
- mPipControlsViewFadeInAnimator = (AnimatorSet) AnimatorInflater.loadAnimator(this,
- R.anim.tv_pip_controls_fade_in);
- mPipControlsViewFadeInAnimator.setTarget(mPipControlsView);
- mPipControlsViewFadeOutAnimator = (AnimatorSet) AnimatorInflater.loadAnimator(this,
- R.anim.tv_pip_controls_fade_out);
- mPipControlsViewFadeOutAnimator.setTarget(mPipControlsView);
+ mPipView = findViewById(R.id.pip);
+ // Place mPipView at the PIP bounds for fine tuned focus handling.
+ Rect pipBounds = mPipManager.getPipBounds();
+ LayoutParams lp = (LayoutParams) mPipView.getLayoutParams();
+ lp.width = pipBounds.width();
+ lp.height = pipBounds.height();
+ lp.leftMargin = pipBounds.left;
+ lp.topMargin = pipBounds.top;
+ mPipView.setLayoutParams(lp);
+
+ mPipRecentsOverlayManager.setCallback(mPipRecentsOverlayManagerCallback);
getWindow().getAttributes().privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
@@ -289,7 +312,6 @@
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent);
- updatePipUI();
mPipManager.addListener(mPipListener);
}
@@ -321,9 +343,7 @@
SystemServicesProxy ssp = Recents.getSystemServices();
EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, true));
- mPipManager.onRecentsStarted();
- // Give focus to the recents row whenever its visible to an user.
- mRecentsView.requestFocus();
+ updatePipUI();
}
@Override
@@ -333,10 +353,21 @@
}
@Override
+ public void onResume() {
+ super.onResume();
+ mPipRecentsOverlayManager.onRecentsResumed();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mPipRecentsOverlayManager.onRecentsPaused();
+ }
+
+ @Override
protected void onStop() {
super.onStop();
- mPipManager.onRecentsStopped();
mIgnoreAltTabRelease = false;
// Notify that recents is now hidden
EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, false));
@@ -480,25 +511,13 @@
private void updatePipUI() {
if (mPipManager.isPipShown()) {
- mPipControlsView.setAlpha(0);
- mPipControlsView.setVisibility(View.VISIBLE);
- mPipShadeView.setVisibility(View.INVISIBLE);
- mPipControlsView.setOnChildFocusChangeListener(new View.OnFocusChangeListener() {
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- mPipManager.onPipViewFocusChangedInRecents(hasFocus);
- if (hasFocus) {
- mPipControlsViewFadeInAnimator.start();
- } else {
- mPipControlsViewFadeOutAnimator.start();
- }
- mPipShadeView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
- }
- });
- mPipShadeView.setVisibility(View.GONE);
+ mPipView.setVisibility(View.VISIBLE);
+ mPipView.setOnFocusChangeListener(mPipViewFocusChangeListener);
+ mPipView.requestFocus();
} else {
- mPipControlsView.setVisibility(View.GONE);
- mPipShadeView.setVisibility(View.GONE);
+ mPipView.setVisibility(View.GONE);
+ mPipRecentsOverlayManager.removePipRecentsOverlayView();
+ mRecentsFocusAnimationHolder.reset();
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/FocusAnimationHolder.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/FocusAnimationHolder.java
new file mode 100644
index 0000000..864540c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/FocusAnimationHolder.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 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.systemui.recents.tv.animations;
+
+import android.content.res.Resources;
+import android.view.View;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.recents.tv.views.TaskCardView;
+
+/**
+ * Collections of Recents row's animation depending on the PIP's focus.
+ */
+public class FocusAnimationHolder {
+ private final float DIM_ALPHA = 0.5f;
+
+ private View mRecentsRowView;
+ private int mCardYDelta;
+ private long mDuration;
+
+ public FocusAnimationHolder(View recentsRowView) {
+ mRecentsRowView = recentsRowView;
+
+ Resources res = recentsRowView.getResources();
+ mCardYDelta = res.getDimensionPixelOffset(R.dimen.recents_tv_dismiss_shift_down);
+ mDuration = res.getInteger(R.integer.recents_tv_pip_focus_anim_duration);
+ }
+
+ public void startFocusGainAnimation() {
+ mRecentsRowView.animate()
+ .setDuration(mDuration)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .alpha(1f)
+ .translationY(0);
+ }
+
+ public void startFocusLoseAnimation() {
+ mRecentsRowView.animate()
+ .setDuration(mDuration)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .alpha(DIM_ALPHA)
+ .translationY(mCardYDelta);
+ }
+
+ public void reset() {
+ mRecentsRowView.setTransitionAlpha(1f);
+ mRecentsRowView.setTranslationY(0);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index da2f721..ef81f9e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -59,7 +59,6 @@
import com.android.systemui.recents.events.activity.LaunchTaskEvent;
import com.android.systemui.recents.events.activity.ShowStackActionButtonEvent;
import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
-import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent;
import com.android.systemui.recents.events.ui.DraggingInRecentsEvent;
@@ -344,10 +343,10 @@
if (RecentsDebugFlags.Static.EnableStackActionButton) {
// Measure the stack action button within the constraints of the space above the stack
- Rect actionButtonRect = mTaskStackView.mLayoutAlgorithm.mStackActionButtonRect;
+ Rect buttonBounds = mTaskStackView.mLayoutAlgorithm.mStackActionButtonRect;
measureChild(mStackActionButton,
- MeasureSpec.makeMeasureSpec(actionButtonRect.width(), MeasureSpec.AT_MOST),
- MeasureSpec.makeMeasureSpec(actionButtonRect.height(), MeasureSpec.AT_MOST));
+ MeasureSpec.makeMeasureSpec(buttonBounds.width(), MeasureSpec.AT_MOST),
+ MeasureSpec.makeMeasureSpec(buttonBounds.height(), MeasureSpec.AT_MOST));
}
setMeasuredDimension(width, height);
@@ -368,24 +367,19 @@
int topBottomInsets = mSystemInsets.top + mSystemInsets.bottom;
int childWidth = mEmptyView.getMeasuredWidth();
int childHeight = mEmptyView.getMeasuredHeight();
- int childLeft = left + Math.max(0, (right - left - leftRightInsets - childWidth)) / 2;
- int childTop = top + Math.max(0, (bottom - top - topBottomInsets - childHeight)) / 2;
+ int childLeft = left + mSystemInsets.left +
+ Math.max(0, (right - left - leftRightInsets - childWidth)) / 2;
+ int childTop = top + mSystemInsets.top +
+ Math.max(0, (bottom - top - topBottomInsets - childHeight)) / 2;
mEmptyView.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
}
if (RecentsDebugFlags.Static.EnableStackActionButton) {
// Layout the stack action button such that its drawable is start-aligned with the
// stack, vertically centered in the available space above the stack
- Rect actionButtonRect = mTaskStackView.mLayoutAlgorithm.mStackActionButtonRect;
- int buttonLeft = isLayoutRtl()
- ? actionButtonRect.right + mStackActionButton.getPaddingStart()
- - mStackActionButton.getMeasuredWidth()
- : actionButtonRect.left - mStackActionButton.getPaddingStart();
- int buttonTop = actionButtonRect.top +
- (actionButtonRect.height() - mStackActionButton.getMeasuredHeight()) / 2;
- mStackActionButton.layout(buttonLeft, buttonTop,
- buttonLeft + mStackActionButton.getMeasuredWidth(),
- buttonTop + mStackActionButton.getMeasuredHeight());
+ Rect buttonBounds = getStackActionButtonBoundsFromStackLayout();
+ mStackActionButton.layout(buttonBounds.left, buttonBounds.top, buttonBounds.right,
+ buttonBounds.bottom);
}
if (mAwaitingFirstLayout) {
@@ -479,6 +473,17 @@
false /* isDefaultDockState */, -1, true /* animateAlpha */,
true /* animateBounds */);
}
+ if (mStackActionButton != null) {
+ event.addPostAnimationCallback(new Runnable() {
+ @Override
+ public void run() {
+ // Move the clear all button to its new position
+ Rect buttonBounds = getStackActionButtonBoundsFromStackLayout();
+ mStackActionButton.setLeftTopRightBottom(buttonBounds.left, buttonBounds.top,
+ buttonBounds.right, buttonBounds.bottom);
+ }
+ });
+ }
}
public final void onBusEvent(final DragEndEvent event) {
@@ -726,13 +731,31 @@
*/
private void animateBackgroundScrim(float alpha, int duration) {
Utilities.cancelAnimationWithoutCallbacks(mBackgroundScrimAnimator);
- int alphaInt = (int) (alpha * 255);
+ // Calculate the absolute alpha to animate from
+ int fromAlpha = (int) ((mBackgroundScrim.getAlpha() / (DEFAULT_SCRIM_ALPHA * 255)) * 255);
+ int toAlpha = (int) (alpha * 255);
mBackgroundScrimAnimator = ObjectAnimator.ofInt(mBackgroundScrim, Utilities.DRAWABLE_ALPHA,
- mBackgroundScrim.getAlpha(), alphaInt);
+ fromAlpha, toAlpha);
mBackgroundScrimAnimator.setDuration(duration);
- mBackgroundScrimAnimator.setInterpolator(alphaInt > mBackgroundScrim.getAlpha()
- ? Interpolators.ALPHA_OUT
- : Interpolators.ALPHA_IN);
+ mBackgroundScrimAnimator.setInterpolator(toAlpha > fromAlpha
+ ? Interpolators.ALPHA_IN
+ : Interpolators.ALPHA_OUT);
mBackgroundScrimAnimator.start();
}
+
+ /**
+ * @return the bounds of the stack action button.
+ */
+ private Rect getStackActionButtonBoundsFromStackLayout() {
+ Rect actionButtonRect = new Rect(mTaskStackView.mLayoutAlgorithm.mStackActionButtonRect);
+ int left = isLayoutRtl()
+ ? actionButtonRect.left - mStackActionButton.getPaddingLeft()
+ : actionButtonRect.right + mStackActionButton.getPaddingRight()
+ - mStackActionButton.getMeasuredWidth();
+ int top = actionButtonRect.top +
+ (actionButtonRect.height() - mStackActionButton.getMeasuredHeight()) / 2;
+ actionButtonRect.set(left, top, left + mStackActionButton.getMeasuredWidth(),
+ top + mStackActionButton.getMeasuredHeight());
+ return actionButtonRect;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index 13ad9a5..07a1d4e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -16,40 +16,58 @@
package com.android.systemui.recents.views;
-import android.app.Activity;
import android.content.Context;
import android.view.View;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsActivity;
+import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
+import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
+import com.android.systemui.recents.misc.SystemServicesProxy;
/** Manages the scrims for the various system bars. */
public class SystemBarScrimViews {
- Context mContext;
+ private static final int DEFAULT_ANIMATION_DURATION = 150;
- View mNavBarScrimView;
+ private Context mContext;
- boolean mHasNavBarScrim;
- boolean mShouldAnimateNavBarScrim;
+ private View mNavBarScrimView;
- int mNavBarScrimEnterDuration;
+ private boolean mHasNavBarScrim;
+ private boolean mShouldAnimateNavBarScrim;
- public SystemBarScrimViews(Activity activity) {
+ private int mNavBarScrimEnterDuration;
+
+ public SystemBarScrimViews(RecentsActivity activity) {
mContext = activity;
mNavBarScrimView = activity.findViewById(R.id.nav_bar_scrim);
+ mNavBarScrimView.forceHasOverlappingRendering(false);
mNavBarScrimEnterDuration = activity.getResources().getInteger(
R.integer.recents_nav_bar_scrim_enter_duration);
}
/**
+ * Updates the nav bar scrim.
+ */
+ public void updateNavBarScrim(boolean animateNavBarScrim, boolean hasStackTasks,
+ AnimationProps animation) {
+ prepareEnterRecentsAnimation(isNavBarScrimRequired(hasStackTasks), animateNavBarScrim);
+ if (animateNavBarScrim && animation != null) {
+ animateNavBarScrimVisibility(true, animation);
+ }
+ }
+
+ /**
* Prepares the scrim views for animating when entering Recents. This will be called before
* the first draw, unless we are updating the scrim on configuration change.
*/
- public void prepareEnterRecentsAnimation(boolean hasNavBarScrim, boolean animateNavBarScrim) {
+ private void prepareEnterRecentsAnimation(boolean hasNavBarScrim, boolean animateNavBarScrim) {
mHasNavBarScrim = hasNavBarScrim;
mShouldAnimateNavBarScrim = animateNavBarScrim;
@@ -60,7 +78,7 @@
/**
* Animates the nav bar scrim visibility.
*/
- public void animateNavBarScrimVisibility(boolean visible, AnimationProps animation) {
+ private void animateNavBarScrimVisibility(boolean visible, AnimationProps animation) {
int toY = 0;
if (visible) {
mNavBarScrimView.setVisibility(View.VISIBLE);
@@ -79,6 +97,14 @@
}
}
+ /**
+ * @return Whether to show the nav bar scrim.
+ */
+ private boolean isNavBarScrimRequired(boolean hasStackTasks) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ return hasStackTasks && !ssp.hasTransposedNavBar() && !ssp.hasDockedTask();
+ }
+
/**** EventBus events ****/
/**
@@ -101,21 +127,48 @@
*/
public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
if (mHasNavBarScrim) {
- AnimationProps animation = new AnimationProps()
- .setDuration(AnimationProps.BOUNDS,
- TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION)
- .setInterpolator(AnimationProps.BOUNDS, Interpolators.FAST_OUT_SLOW_IN);
+ AnimationProps animation = createBoundsAnimation(
+ TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION);
animateNavBarScrimVisibility(false, animation);
}
}
public final void onBusEvent(DismissAllTaskViewsEvent event) {
if (mHasNavBarScrim) {
- AnimationProps animation = new AnimationProps()
- .setDuration(AnimationProps.BOUNDS,
- TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION)
- .setInterpolator(AnimationProps.BOUNDS, Interpolators.FAST_OUT_SLOW_IN);
+ AnimationProps animation = createBoundsAnimation(
+ TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION);
animateNavBarScrimVisibility(false, animation);
}
}
+
+ public final void onBusEvent(ConfigurationChangedEvent event) {
+ animateScrimToCurrentNavBarState(event.hasStackTasks);
+ }
+
+ public final void onBusEvent(MultiWindowStateChangedEvent event) {
+ animateScrimToCurrentNavBarState(event.hasStackTasks);
+ }
+
+ /**
+ * Animates the scrim to match the state of the current nav bar.
+ */
+ private void animateScrimToCurrentNavBarState(boolean hasStackTasks) {
+ boolean hasNavBarScrim = isNavBarScrimRequired(hasStackTasks);
+ if (mHasNavBarScrim != hasNavBarScrim) {
+ AnimationProps animation = hasNavBarScrim
+ ? createBoundsAnimation(DEFAULT_ANIMATION_DURATION)
+ : AnimationProps.IMMEDIATE;
+ animateNavBarScrimVisibility(hasNavBarScrim, animation);
+ }
+ mHasNavBarScrim = hasNavBarScrim;
+ }
+
+ /**
+ * @return a default animation to aniamte the bounds of the scrim.
+ */
+ private AnimationProps createBoundsAnimation(int duration) {
+ return new AnimationProps()
+ .setDuration(AnimationProps.BOUNDS, duration)
+ .setInterpolator(AnimationProps.BOUNDS, Interpolators.FAST_OUT_SLOW_IN);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index 2508304..9eab0f6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -537,11 +537,13 @@
} else {
mInitialScrollP = Utilities.clamp(launchTaskIndex - 1, mMinScrollP, mMaxScrollP);
}
+ mInitialNormX = null;
} else if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1) {
// If there is one stack task, ignore the min/max/initial scroll positions
mMinScrollP = 0;
mMaxScrollP = 0;
mInitialScrollP = 0;
+ mInitialNormX = null;
} else {
// Set the max scroll to be the point where the front most task is visible with the
// stack bottom offset
@@ -803,8 +805,9 @@
public TaskViewTransform getStackTransformScreenCoordinates(Task task, float stackScroll,
TaskViewTransform transformOut, TaskViewTransform frontTransform) {
Rect windowRect = Recents.getSystemServices().getWindowRect();
- TaskViewTransform transform = getStackTransform(task, stackScroll, transformOut,
- frontTransform);
+ TaskViewTransform transform = getStackTransform(task, stackScroll, mFocusState,
+ transformOut, frontTransform, true /* forceUpdate */,
+ false /* ignoreTaskOverrides */);
transform.rect.offset(windowRect.left, windowRect.top);
return transform;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index ddea4d9..570ff8a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -267,9 +267,9 @@
lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.START | Gravity.CENTER_VERTICAL);
lp.setMarginStart(mHeaderBarHeight);
- lp.rightMargin = mMoveTaskButton != null
+ lp.setMarginEnd(mMoveTaskButton != null
? 2 * mHeaderBarHeight
- : mHeaderBarHeight;
+ : mHeaderBarHeight);
title.setLayoutParams(lp);
if (secondaryButton != null) {
lp = new FrameLayout.LayoutParams(mHeaderBarHeight, mHeaderBarHeight, Gravity.END);
@@ -459,7 +459,7 @@
if (!mTitleView.getText().toString().equals(t.title)) {
mTitleView.setText(t.title);
}
- mTitleView.setContentDescription(t.contentDescription);
+ mTitleView.setContentDescription(t.titleDescription);
mTitleView.setTextColor(t.useLightOnPrimaryColor ?
mTaskBarViewLightTextColor : mTaskBarViewDarkTextColor);
if (!t.isDockable && ssp.hasDockedTask()) {
@@ -501,6 +501,7 @@
// In accessibility, a single click on the focused app info button will show it
if (touchExplorationEnabled) {
+ mIconView.setContentDescription(t.appInfoDescription);
mIconView.setOnClickListener(this);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index 3eeabc7..e5ac0d3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -141,9 +141,9 @@
return;
}
+ int viewWidth = mTaskViewRect.width();
+ int viewHeight = mTaskViewRect.height();
if (mBitmapShader != null) {
- int viewWidth = mTaskViewRect.width();
- int viewHeight = mTaskViewRect.height();
// We are drawing the thumbnail in the same orientation, so just fit the width
int thumbnailWidth = (int) (mThumbnailRect.width() * mThumbnailScale);
@@ -180,6 +180,9 @@
canvas.restoreToCount(count);
}
+ } else {
+ canvas.drawRoundRect(0, 0, viewWidth, viewHeight, mCornerRadius, mCornerRadius,
+ mBgFillPaint);
}
}
@@ -319,12 +322,12 @@
mDisabledInSafeMode = disabledInSafeMode;
if (t.thumbnail != null) {
setThumbnail(t.thumbnail, thumbnailInfo);
- if (t.colorBackground != 0) {
- mBgFillPaint.setColor(t.colorBackground);
- }
} else {
setThumbnail(null, null);
}
+ if (t.colorBackground != 0) {
+ mBgFillPaint.setColor(t.colorBackground);
+ }
}
/** Unbinds the thumbnail view from the task */
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index e8cf126..ddd3ea1 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -97,6 +97,9 @@
if (mVisible != visible) {
mVisible = visible;
mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+
+ // Update state because animations won't finish.
+ mView.setMinimizedDockStack(mMinimized);
}
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 7a933cd..601d910 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -134,6 +134,7 @@
private ValueAnimator mCurrentAnimator;
private boolean mEntranceAnimationRunning;
private GestureDetector mGestureDetector;
+ private boolean mDockedStackMinimized;
private final AccessibilityDelegate mHandleDelegate = new AccessibilityDelegate() {
@Override
@@ -538,6 +539,7 @@
: mBackground.getWidth());
mBackground.setScaleX(MINIMIZE_DOCK_SCALE);
}
+ mDockedStackMinimized = minimized;
}
public void setMinimizedDockStack(boolean minimized, long animDuration) {
@@ -566,6 +568,7 @@
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.setDuration(animDuration)
.start();
+ mDockedStackMinimized = minimized;
}
private void resetBackground() {
@@ -883,7 +886,7 @@
public final void onBusEvent(UndockingTaskEvent undockingTaskEvent) {
int dockSide = mWindowManagerProxy.getDockSide();
- if (dockSide != WindowManager.DOCKED_INVALID) {
+ if (dockSide != WindowManager.DOCKED_INVALID && !mDockedStackMinimized) {
startDragging(false /* animate */, false /* touching */);
SnapTarget target = dockSideTopLeft(dockSide)
? mSnapAlgorithm.getDismissEndTarget()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 1c5d28a..f5f5a92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -19,7 +19,9 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.ActivityManager;
+import android.app.ActivityManager.StackId;
import android.app.ActivityManagerNative;
+import android.app.ActivityOptions;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
@@ -127,6 +129,8 @@
SystemProperties.getBoolean("debug.enable_remote_input", true);
public static final boolean ENABLE_CHILD_NOTIFICATIONS
= SystemProperties.getBoolean("debug.child_notifs", true);
+ public static final boolean FORCE_REMOTE_INPUT_HISTORY =
+ SystemProperties.getBoolean("debug.force_remoteinput_history", false);
protected static final int MSG_SHOW_RECENT_APPS = 1019;
protected static final int MSG_HIDE_RECENT_APPS = 1020;
@@ -182,6 +186,13 @@
protected boolean mVisible;
protected ArraySet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new ArraySet<>();
+ /**
+ * Notifications with keys in this set are not actually around anymore. We kept them around
+ * when they were canceled in response to a remote input interaction. This allows us to show
+ * what you replied and allows you to continue typing into it.
+ */
+ protected ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>();
+
// mScreenOnFromKeyguard && mVisible.
private boolean mVisibleToUser;
@@ -338,7 +349,7 @@
}, afterKeyguardGone);
return true;
} else {
- return super.onClickHandler(view, pendingIntent, fillInIntent);
+ return superOnClickHandler(view, pendingIntent, fillInIntent);
}
}
@@ -375,7 +386,8 @@
private boolean superOnClickHandler(View view, PendingIntent pendingIntent,
Intent fillInIntent) {
- return super.onClickHandler(view, pendingIntent, fillInIntent);
+ return super.onClickHandler(view, pendingIntent, fillInIntent,
+ StackId.FULLSCREEN_WORKSPACE_STACK_ID);
}
private boolean handleRemoteInput(View view, PendingIntent pendingIntent, Intent fillInIntent) {
@@ -566,6 +578,7 @@
public void run() {
processForRemoteInput(sbn.getNotification());
String key = sbn.getKey();
+ mKeysKeptForRemoteInput.remove(key);
boolean isUpdate = mNotificationData.get(key) != null;
// In case we don't allow child notifications, we ignore children of
// notifications that have a summary, since we're not going to show them
@@ -904,7 +917,7 @@
}
}
- protected View bindVetoButtonClickListener(View row, StatusBarNotification n) {
+ protected View bindVetoButtonClickListener(View row, final StatusBarNotification n) {
View vetoButton = row.findViewById(R.id.veto);
final String _pkg = n.getPackageName();
final String _tag = n.getTag();
@@ -917,6 +930,11 @@
mContext.getString(R.string.accessibility_notification_dismissed));
try {
mBarService.onNotificationClear(_pkg, _tag, _id, _userId);
+ if (FORCE_REMOTE_INPUT_HISTORY
+ && mKeysKeptForRemoteInput.contains(n.getKey())) {
+ removeNotification(n.getKey(), null);
+ mKeysKeptForRemoteInput.remove(n.getKey());
+ }
} catch (RemoteException ex) {
// system process is dead if we're here.
@@ -975,7 +993,7 @@
}
TaskStackBuilder.create(mContext)
.addNextIntentWithParentStack(intent)
- .startActivities(null,
+ .startActivities(getActivityOptions(),
new UserHandle(UserHandle.getUserId(appUid)));
overrideActivityPendingAppTransition(keyguardShowing);
} catch (RemoteException e) {
@@ -1725,7 +1743,7 @@
} catch (RemoteException e) {
}
try {
- intent.send();
+ intent.send(null, 0, null, null, null, null, getActivityOptions());
} catch (PendingIntent.CanceledException e) {
// the stack trace isn't very helpful here.
// Just log the exception message.
@@ -1825,15 +1843,17 @@
.getIdentifier();
if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
&& mKeyguardManager.isDeviceLocked(userId)) {
- // Show work challenge, do not run pendingintent and
- // remove notification
- startWorkChallenge(userId, intent.getIntentSender(),
- notificationKey);
- return;
+ if (startWorkChallengeIfNecessary(userId,
+ intent.getIntentSender(), notificationKey)) {
+ // Show work challenge, do not run pendingintent and
+ // remove notification
+ return;
+ }
}
}
try {
- intent.send();
+ intent.send(null, 0, null, null, null, null,
+ getActivityOptions());
} catch (PendingIntent.CanceledException e) {
// the stack trace isn't very helpful here.
// Just log the exception message.
@@ -1866,21 +1886,25 @@
}, afterKeyguardGone);
}
- public void startWorkChallenge(int userId, IntentSender intendSender,
+ public boolean startWorkChallengeIfNecessary(int userId, IntentSender intendSender,
String notificationKey) {
+ final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null,
+ null, userId);
+ if (newIntent == null) {
+ return false;
+ }
final Intent callBackIntent = new Intent(
WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION);
callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender);
callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
callBackIntent.setPackage(mContext.getPackageName());
- final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null,
- null, userId);
newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | Intent.FLAG_ACTIVITY_CLEAR_TASK);
newIntent.putExtra(Intent.EXTRA_INTENT, PendingIntent
.getBroadcast(mContext, 0, callBackIntent, 0).getIntentSender());
mContext.startActivity(newIntent);
+ return true;
}
public void register(ExpandableNotificationRow row, StatusBarNotification sbn) {
@@ -1909,6 +1933,14 @@
}
}
+ protected Bundle getActivityOptions() {
+ // Anything launched from the notification shade should always go into the
+ // fullscreen stack.
+ ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchStackId(StackId.FULLSCREEN_WORKSPACE_STACK_ID);
+ return options.toBundle();
+ }
+
protected void visibilityChanged(boolean visible) {
if (mVisible != visible) {
mVisible = visible;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index 7f87c3c..2dabf5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -170,22 +170,22 @@
: RUBBERBAND_FACTOR_STATIC;
float rubberband = heightDelta * rubberbandFactor;
if (expandable
- && (rubberband + child.getMinExpandHeight()) > child.getMaxContentHeight()) {
+ && (rubberband + child.getCollapsedHeight()) > child.getMaxContentHeight()) {
float overshoot =
- (rubberband + child.getMinExpandHeight()) - child.getMaxContentHeight();
+ (rubberband + child.getCollapsedHeight()) - child.getMaxContentHeight();
overshoot *= (1 - RUBBERBAND_FACTOR_STATIC);
rubberband -= overshoot;
}
- child.setActualHeight((int) (child.getMinExpandHeight() + rubberband));
+ child.setActualHeight((int) (child.getCollapsedHeight() + rubberband));
}
private void cancelExpansion(final ExpandableView child) {
- if (child.getActualHeight() == child.getMinExpandHeight()) {
+ if (child.getActualHeight() == child.getCollapsedHeight()) {
mCallback.setUserLockedChild(child, false);
return;
}
ObjectAnimator anim = ObjectAnimator.ofInt(child, "actualHeight",
- child.getActualHeight(), child.getMinExpandHeight());
+ child.getActualHeight(), child.getCollapsedHeight());
anim.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
anim.setDuration(SPRING_BACK_ANIMATION_LENGTH_MS);
anim.addListener(new AnimatorListenerAdapter() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index f9edeb3..7ca7d12 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -470,7 +470,7 @@
if(mExpandedWhenPinned) {
return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
} else if (atLeastMinHeight) {
- return Math.max(getMinHeight(), mHeadsUpHeight);
+ return Math.max(getCollapsedHeight(), mHeadsUpHeight);
} else {
return mHeadsUpHeight;
}
@@ -1040,12 +1040,12 @@
} else if (isExpanded()) {
return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
} else {
- return Math.max(getMinHeight(), mHeadsUpHeight);
+ return Math.max(getCollapsedHeight(), mHeadsUpHeight);
}
} else if (isExpanded()) {
return getMaxExpandHeight();
} else {
- return getMinHeight();
+ return getCollapsedHeight();
}
}
@@ -1301,9 +1301,9 @@
}
@Override
- public int getMinExpandHeight() {
+ public int getCollapsedHeight() {
if (mIsSummaryWithChildren && !mShowingPublic) {
- return mChildrenContainer.getMinExpandHeight();
+ return mChildrenContainer.getCollapsedHeight();
}
return getMinHeight();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 91418ad..6dcd61f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -153,11 +153,11 @@
}
/**
- * @return The minimum height this child chan be expanded to. Note that this might be different
- * than {@link #getMinHeight()} because some elements can't be collapsed by an expand gesture
- * to it's absolute minimal height
+ * @return The collapsed height of this view. Note that this might be different
+ * than {@link #getMinHeight()} because some elements like groups may have different sizes when
+ * they are system expanded.
*/
- public int getMinExpandHeight() {
+ public int getCollapsedHeight() {
return getHeight();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index 8fe60a0..2b365dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -245,7 +245,57 @@
systemGroup.addItem(new KeyboardShortcutInfo(
mContext.getString(R.string.keyboard_shortcut_group_system_recents),
KeyEvent.KEYCODE_TAB, KeyEvent.META_ALT_ON));
+ systemGroup.addItem(new KeyboardShortcutInfo(
+ mContext.getString(
+ R.string.keyboard_shortcut_group_system_notifications),
+ KeyEvent.KEYCODE_N, KeyEvent.META_META_ON));
+ systemGroup.addItem(new KeyboardShortcutInfo(
+ mContext.getString(
+ R.string.keyboard_shortcut_group_system_shortcuts_helper),
+ KeyEvent.KEYCODE_SLASH, KeyEvent.META_META_ON));
+ systemGroup.addItem(new KeyboardShortcutInfo(
+ mContext.getString(
+ R.string.keyboard_shortcut_group_system_switch_input),
+ KeyEvent.KEYCODE_SPACE, KeyEvent.META_META_ON));
result.add(systemGroup);
+
+ KeyboardShortcutGroup applicationGroup = new KeyboardShortcutGroup(
+ mContext.getString(R.string.keyboard_shortcut_group_applications),
+ true);
+ applicationGroup.addItem(new KeyboardShortcutInfo(
+ mContext.getString(
+ R.string.keyboard_shortcut_group_applications_assist),
+ KeyEvent.KEYCODE_UNKNOWN, KeyEvent.META_META_ON));
+ applicationGroup.addItem(new KeyboardShortcutInfo(
+ mContext.getString(
+ R.string.keyboard_shortcut_group_applications_browser),
+ KeyEvent.KEYCODE_B, KeyEvent.META_META_ON));
+ applicationGroup.addItem(new KeyboardShortcutInfo(
+ mContext.getString(
+ R.string.keyboard_shortcut_group_applications_contacts),
+ KeyEvent.KEYCODE_C, KeyEvent.META_META_ON));
+ applicationGroup.addItem(new KeyboardShortcutInfo(
+ mContext.getString(
+ R.string.keyboard_shortcut_group_applications_email),
+ KeyEvent.KEYCODE_E, KeyEvent.META_META_ON));
+ applicationGroup.addItem(new KeyboardShortcutInfo(
+ mContext.getString(
+ R.string.keyboard_shortcut_group_applications_im),
+ KeyEvent.KEYCODE_T, KeyEvent.META_META_ON));
+ applicationGroup.addItem(new KeyboardShortcutInfo(
+ mContext.getString(
+ R.string.keyboard_shortcut_group_applications_music),
+ KeyEvent.KEYCODE_P, KeyEvent.META_META_ON));
+ applicationGroup.addItem(new KeyboardShortcutInfo(
+ mContext.getString(
+ R.string.keyboard_shortcut_group_applications_youtube),
+ KeyEvent.KEYCODE_Y, KeyEvent.META_META_ON));
+ applicationGroup.addItem(new KeyboardShortcutInfo(
+ mContext.getString(
+ R.string.keyboard_shortcut_group_applications_calendar),
+ KeyEvent.KEYCODE_L, KeyEvent.META_META_ON));
+ result.add(applicationGroup);
+
showKeyboardShortcutsDialog(result);
}
}, deviceId);
@@ -354,11 +404,15 @@
return null;
}
String displayLabelString;
- if (info.getKeycode() == KeyEvent.KEYCODE_UNKNOWN) {
+ if (info.getBaseCharacter() > Character.MIN_VALUE) {
displayLabelString = String.valueOf(info.getBaseCharacter());
} else if (SPECIAL_CHARACTER_NAMES.get(info.getKeycode()) != null) {
displayLabelString = SPECIAL_CHARACTER_NAMES.get(info.getKeycode());
} else {
+ // Special case for shortcuts with no base key or keycode.
+ if (info.getKeycode() == KeyEvent.KEYCODE_UNKNOWN) {
+ return shortcutKeys;
+ }
// TODO: Have a generic map for when we don't have the device's.
char displayLabel = mKeyCharacterMap == null
? 0 : mKeyCharacterMap.getDisplayLabel(info.getKeycode());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index f4fb0b9..5b00523 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -604,7 +604,7 @@
}
int expandedVisualType = getVisualTypeForHeight(height);
int collapsedVisualType = getVisualTypeForHeight(
- mContainingNotification.getMinExpandHeight());
+ mContainingNotification.getCollapsedHeight());
return mTransformationStartVisibleType == collapsedVisualType
? expandedVisualType
: collapsedVisualType;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java
index a3e78c1..88aafe0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java
@@ -92,7 +92,7 @@
mAnimating = false;
mSnapping = false;
mDismissing = false;
- setIconLocation(true /* on left */);
+ setIconLocation(true /* on left */, true /* force */);
if (mListener != null) {
mListener.onSettingsIconRowReset(this);
}
@@ -104,6 +104,7 @@
public void setNotificationRowParent(ExpandableNotificationRow parent) {
mParent = parent;
+ setIconLocation(mOnLeft, true /* force */);
}
public void setAppName(String appName) {
@@ -183,7 +184,7 @@
if (isIconLocationChange(transX)) {
setGearAlpha(0f);
}
- setIconLocation(transX > 0 /* fromLeft */);
+ setIconLocation(transX > 0 /* fromLeft */, false /* force */);
mFadeAnimator = ValueAnimator.ofFloat(mGearIcon.getAlpha(), 1);
mFadeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
@@ -220,12 +221,20 @@
mFadeAnimator.start();
}
- public void setIconLocation(boolean onLeft) {
- if (onLeft == mOnLeft || mSnapping) {
- // Same side? Do nothing.
+ @Override
+ public void onRtlPropertiesChanged(int layoutDirection) {
+ setIconLocation(mOnLeft, true /* force */);
+ }
+
+ public void setIconLocation(boolean onLeft, boolean force) {
+ if ((!force && onLeft == mOnLeft) || mSnapping || mParent == null) {
+ // Do nothing
return;
}
- setTranslationX(onLeft ? 0 : (mParent.getWidth() - mHorizSpaceForGear));
+ final boolean isRtl = mParent.isLayoutRtl();
+ final float left = isRtl ? -(mParent.getWidth() - mHorizSpaceForGear) : 0;
+ final float right = isRtl ? 0 : (mParent.getWidth() - mHorizSpaceForGear);
+ setTranslationX(onLeft ? left : right);
mOnLeft = onLeft;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
index d7e47c2..5fea674 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -21,6 +21,8 @@
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.RemoteInputView;
+import android.util.ArraySet;
+
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -29,7 +31,8 @@
*/
public class RemoteInputController {
- private final ArrayList<WeakReference<NotificationData.Entry>> mRemoteInputs = new ArrayList<>();
+ private final ArrayList<WeakReference<NotificationData.Entry>> mOpen = new ArrayList<>();
+ private final ArraySet<String> mSpinning = new ArraySet<>();
private final ArrayList<Callback> mCallbacks = new ArrayList<>(3);
private final HeadsUpManager mHeadsUpManager;
@@ -44,7 +47,7 @@
boolean found = pruneWeakThenRemoveAndContains(
entry /* contains */, null /* remove */);
if (!found) {
- mRemoteInputs.add(new WeakReference<>(entry));
+ mOpen.add(new WeakReference<>(entry));
}
apply(entry);
@@ -58,6 +61,18 @@
apply(entry);
}
+ public void addSpinning(String key) {
+ mSpinning.add(key);
+ }
+
+ public void removeSpinning(String key) {
+ mSpinning.remove(key);
+ }
+
+ public boolean isSpinning(String key) {
+ return mSpinning.contains(key);
+ }
+
private void apply(NotificationData.Entry entry) {
mHeadsUpManager.setRemoteInputActive(entry, isRemoteInputActive(entry));
boolean remoteInputActive = isRemoteInputActive();
@@ -79,7 +94,7 @@
*/
public boolean isRemoteInputActive() {
pruneWeakThenRemoveAndContains(null /* contains */, null /* remove */);
- return !mRemoteInputs.isEmpty();
+ return !mOpen.isEmpty();
}
/**
@@ -91,10 +106,10 @@
private boolean pruneWeakThenRemoveAndContains(
NotificationData.Entry contains, NotificationData.Entry remove) {
boolean found = false;
- for (int i = mRemoteInputs.size() - 1; i >= 0; i--) {
- NotificationData.Entry item = mRemoteInputs.get(i).get();
+ for (int i = mOpen.size() - 1; i >= 0; i--) {
+ NotificationData.Entry item = mOpen.get(i).get();
if (item == null || item == remove) {
- mRemoteInputs.remove(i);
+ mOpen.remove(i);
} else if (item == contains) {
found = true;
}
@@ -108,7 +123,16 @@
mCallbacks.add(callback);
}
+ public void remoteInputSent(NotificationData.Entry entry) {
+ int N = mCallbacks.size();
+ for (int i = 0; i < N; i++) {
+ mCallbacks.get(i).onRemoteInputSent(entry);
+ }
+ }
+
public interface Callback {
- void onRemoteInputActive(boolean active);
+ default void onRemoteInputActive(boolean active) {}
+
+ default void onRemoteInputSent(NotificationData.Entry entry) {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.java
index 04095e7..3fdc35c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.java
@@ -23,6 +23,7 @@
public class ExpandableIndicator extends ImageView {
private boolean mExpanded;
+ private boolean mIsDefaultDirection = true;
public ExpandableIndicator(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -31,16 +32,14 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- final int res = mExpanded ? R.drawable.ic_volume_collapse_animation
- : R.drawable.ic_volume_expand_animation;
+ final int res = getDrawableResourceId(mExpanded);
setImageResource(res);
}
public void setExpanded(boolean expanded) {
if (expanded == mExpanded) return;
mExpanded = expanded;
- final int res = mExpanded ? R.drawable.ic_volume_expand_animation
- : R.drawable.ic_volume_collapse_animation;
+ final int res = getDrawableResourceId(!mExpanded);
// workaround to reset drawable
final AnimatedVectorDrawable avd = (AnimatedVectorDrawable) getContext()
.getDrawable(res).getConstantState().newDrawable();
@@ -48,4 +47,19 @@
avd.forceAnimationOnUI();
avd.start();
}
+
+ /** Whether the icons are using the default direction or the opposite */
+ public void setDefaultDirection(boolean isDefaultDirection) {
+ mIsDefaultDirection = isDefaultDirection;
+ }
+
+ private int getDrawableResourceId(boolean expanded) {
+ if (mIsDefaultDirection) {
+ return expanded ? R.drawable.ic_volume_collapse_animation
+ : R.drawable.ic_volume_expand_animation;
+ } else {
+ return expanded ? R.drawable.ic_volume_expand_animation
+ : R.drawable.ic_volume_collapse_animation;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index 65e7973..3812429 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -85,7 +85,7 @@
// wallpaper.
final int lockWallpaperUserId =
mSelectedUser != null ? mSelectedUser.getIdentifier() : mCurrentUserId;
- ParcelFileDescriptor fd = mService.getWallpaper(null, WallpaperManager.FLAG_SET_LOCK,
+ ParcelFileDescriptor fd = mService.getWallpaper(null, WallpaperManager.FLAG_LOCK,
new Bundle(), lockWallpaperUserId);
if (fd != null) {
try {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java
index 63ee0c0..41eed56 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java
@@ -113,7 +113,8 @@
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
- filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, null);
} else {
mContext.unregisterReceiver(mReceiver);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index 960515b..35fb2a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -35,6 +35,7 @@
public class NotificationsQuickSettingsContainer extends FrameLayout
implements ViewStub.OnInflateListener, DensityContainer.InflateListener {
+
private DensityContainer mQsContainer;
private View mUserSwitcher;
private View mStackScroller;
@@ -43,6 +44,9 @@
private boolean mQsExpanded;
private boolean mCustomizerAnimating;
+ private int mBottomPadding;
+ private int mStackScrollerMargin;
+
public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -53,6 +57,7 @@
mQsContainer = (DensityContainer) findViewById(R.id.qs_density_container);
mQsContainer.addInflateListener(this);
mStackScroller = findViewById(R.id.notification_stack_scroller);
+ mStackScrollerMargin = ((LayoutParams) mStackScroller.getLayoutParams()).bottomMargin;
mKeyguardStatusBar = findViewById(R.id.keyguard_header);
ViewStub userSwitcher = (ViewStub) findViewById(R.id.keyguard_user_switcher);
userSwitcher.setOnInflateListener(this);
@@ -75,7 +80,8 @@
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- setPadding(0, 0, 0, insets.getStableInsetBottom());
+ mBottomPadding = insets.getStableInsetBottom();
+ setPadding(0, 0, 0, mBottomPadding);
return insets;
}
@@ -141,4 +147,22 @@
invalidate();
}
}
+
+ public void setCustomizerShowing(boolean isShowing) {
+ if (isShowing) {
+ // Clear out bottom paddings/margins so the qs customization can be full height.
+ setPadding(0, 0, 0, 0);
+ setBottomMargin(mStackScroller, 0);
+ } else {
+ setPadding(0, 0, 0, mBottomPadding);
+ setBottomMargin(mStackScroller, mStackScrollerMargin);
+ }
+
+ }
+
+ private void setBottomMargin(View v, int bottomMargin) {
+ LayoutParams params = (LayoutParams) v.getLayoutParams();
+ params.bottomMargin = bottomMargin;
+ v.setLayoutParams(params);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index bb77c5b..c563eb6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -21,7 +21,9 @@
import android.animation.AnimatorListenerAdapter;
import android.annotation.NonNull;
import android.app.ActivityManager;
+import android.app.ActivityManager.StackId;
import android.app.ActivityManagerNative;
+import android.app.ActivityOptions;
import android.app.IActivityManager;
import android.app.Notification;
import android.app.PendingIntent;
@@ -876,7 +878,7 @@
DensityContainer container = (DensityContainer) mStatusBarWindow.findViewById(
R.id.qs_density_container);
if (container != null) {
- final QSTileHost qsh = new QSTileHost(mContext, this,
+ final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
mBluetoothController, mLocationController, mRotationLockController,
mNetworkController, mZenModeController, mHotspotController,
mCastController, mFlashlightController,
@@ -1110,6 +1112,18 @@
mStatusBarKeyguardViewManager);
mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mRemoteInputController.addCallback(mStatusBarKeyguardViewManager);
+
+ if (FORCE_REMOTE_INPUT_HISTORY) {
+ mRemoteInputController.addCallback(new RemoteInputController.Callback() {
+ @Override
+ public void onRemoteInputSent(Entry entry) {
+ if (mKeysKeptForRemoteInput.contains(entry.key)) {
+ removeNotification(entry.key, null);
+ }
+ }
+ });
+ }
+
mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
mLightStatusBarController.setFingerprintUnlockController(mFingerprintUnlockController);
}
@@ -1378,6 +1392,42 @@
clearCurrentMediaNotification();
updateMediaMetaData(true, true);
}
+ if (FORCE_REMOTE_INPUT_HISTORY && mRemoteInputController.isSpinning(key)) {
+ Entry entry = mNotificationData.get(key);
+ StatusBarNotification sbn = entry.notification;
+
+ Notification.Builder b = Notification.Builder
+ .recoverBuilder(mContext, sbn.getNotification().clone());
+ CharSequence[] oldHistory = sbn.getNotification().extras
+ .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY);
+ CharSequence[] newHistory;
+ if (oldHistory == null) {
+ newHistory = new CharSequence[1];
+ } else {
+ newHistory = new CharSequence[oldHistory.length + 1];
+ for (int i = 0; i < oldHistory.length; i++) {
+ newHistory[i + 1] = oldHistory[i];
+ }
+ }
+ newHistory[0] = String.valueOf(entry.remoteInputText);
+ b.setRemoteInputHistory(newHistory);
+
+ Notification newNotification = b.build();
+
+ // Undo any compatibility view inflation
+ newNotification.contentView = sbn.getNotification().contentView;
+ newNotification.bigContentView = sbn.getNotification().bigContentView;
+ newNotification.headsUpContentView = sbn.getNotification().headsUpContentView;
+
+ StatusBarNotification newSbn = new StatusBarNotification(sbn.getPackageName(),
+ sbn.getOpPkg(),
+ sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
+ 0, newNotification, sbn.getUser(), sbn.getPostTime());
+
+ updateNotification(newSbn, null);
+ mKeysKeptForRemoteInput.add(entry.key);
+ return;
+ }
if (deferRemoval) {
mLatestRankingMap = ranking;
mHeadsUpEntriesToRemoveOnSwitch.add(mHeadsUpManager.getEntry(key));
@@ -3043,8 +3093,8 @@
null, mContext.getBasePackageName(),
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, null,
- UserHandle.CURRENT.getIdentifier());
+ null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null,
+ getActivityOptions(), UserHandle.CURRENT.getIdentifier());
} catch (RemoteException e) {
Log.w(TAG, "Unable to start activity", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index c883cc9..0ac2e7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -137,7 +137,8 @@
filter.addAction(AudioManager.ACTION_HEADSET_PLUG);
filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED);
- filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
// listen for user / profile change.
@@ -507,7 +508,8 @@
updateSimState(intent);
} else if (action.equals(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED)) {
updateTTY(intent);
- } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED)) {
+ } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_AVAILABLE) ||
+ action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
updateQuietState();
updateManagedProfile();
} else if (action.equals(AudioManager.ACTION_HEADSET_PLUG)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 5dcd393..82496ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -81,7 +81,7 @@
import java.util.Map;
/** Platform implementation of the quick settings tile host **/
-public final class QSTileHost implements QSTile.Host, Tunable {
+public class QSTileHost implements QSTile.Host, Tunable {
private static final String TAG = "QSTileHost";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -450,7 +450,7 @@
}
}
- public static List<String> loadTileSpecs(Context context, String tileList) {
+ protected List<String> loadTileSpecs(Context context, String tileList) {
final Resources res = context.getResources();
final String defaultTileList = res.getString(R.string.quick_settings_tiles_default);
if (tileList == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index b507903..f3aba4f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -68,7 +68,7 @@
private ViewGroup mDateTimeAlarmGroup;
private TextView mEmergencyOnly;
- private ExpandableIndicator mExpandIndicator;
+ protected ExpandableIndicator mExpandIndicator;
private boolean mListening;
private AlarmManager.AlarmClockInfo mNextAlarm;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 1f4ef4a..557f166 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -121,8 +121,11 @@
mEditText.setEnabled(false);
mSendButton.setVisibility(INVISIBLE);
mProgressBar.setVisibility(VISIBLE);
+ mEntry.remoteInputText = mEditText.getText();
+ mController.addSpinning(mEntry.key);
mController.removeRemoteInput(mEntry);
mEditText.mShowImeOnInputConnection = false;
+ mController.remoteInputSent(mEntry);
try {
mPendingIntent.send(mContext, 0, fillInIntent);
@@ -177,6 +180,7 @@
return;
}
mController.removeRemoteInput(mEntry);
+ mController.removeSpinning(mEntry.key);
}
public void setPendingIntent(PendingIntent pendingIntent) {
@@ -213,6 +217,7 @@
mEditText.setEnabled(true);
mSendButton.setVisibility(VISIBLE);
mProgressBar.setVisibility(INVISIBLE);
+ mController.removeSpinning(mEntry.key);
updateSendButton();
onDefocus();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index dc567fc..2f4e799 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -592,7 +592,7 @@
public float getGroupExpandFraction() {
int visibleChildrenExpandedHeight = getVisibleChildrenExpandHeight();
- int minExpandHeight = getMinExpandHeight();
+ int minExpandHeight = getCollapsedHeight();
float factor = (mActualHeight - minExpandHeight)
/ (float) (visibleChildrenExpandedHeight - minExpandHeight);
return Math.max(0.0f, Math.min(1.0f, factor));
@@ -618,11 +618,14 @@
}
public int getMinHeight() {
- return getIntrinsicHeight(NUMBER_OF_CHILDREN_WHEN_COLLAPSED);
+ return getMinHeight(NUMBER_OF_CHILDREN_WHEN_COLLAPSED);
}
- public int getMinExpandHeight() {
- int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* forceCollapsed */);
+ public int getCollapsedHeight() {
+ return getMinHeight(getMaxAllowedVisibleChildren(true /* forceCollapsed */));
+ }
+
+ private int getMinHeight(int maxAllowedVisibleChildren) {
int minExpandHeight = mNotificationHeaderHeight;
int visibleChildren = 0;
boolean firstChild = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index b5030e6..bb1de04 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -1947,7 +1947,7 @@
public int getPeekHeight() {
final ExpandableView firstChild = getFirstChildNotGone();
- final int firstChildMinHeight = firstChild != null ? (int) firstChild.getMinHeight()
+ final int firstChildMinHeight = firstChild != null ? firstChild.getCollapsedHeight()
: mCollapsedSize;
return mIntrinsicPadding + firstChildMinHeight + mBottomStackPeekSize
+ mBottomStackSlowDownHeight;
@@ -3532,7 +3532,8 @@
} else {
// Check scheduled, reset alpha and update location; check will fade it in
mCurrIconRow.setGearAlpha(0f);
- mCurrIconRow.setIconLocation(translation > 0 /* onLeft */);
+ mCurrIconRow.setIconLocation(translation > 0 /* onLeft */,
+ false /* force */);
}
}
}
@@ -3547,8 +3548,9 @@
}
@Override
- public void dismissChild(final View view, float velocity) {
- super.dismissChild(view, velocity);
+ public void dismissChild(final View view, float velocity,
+ boolean useAccelerateInterpolator) {
+ super.dismissChild(view, velocity, useAccelerateInterpolator);
cancelCheckForDrag();
setSnappedToGear(false);
}
@@ -3584,7 +3586,8 @@
snapChild(animView, 0 /* leftTarget */, velocity);
} else if (isDismissGesture(ev)) {
// Gesture is a dismiss that's not towards the gear
- dismissChild(animView, swipedFastEnough() ? velocity : 0f);
+ dismissChild(animView, velocity,
+ !swipedFastEnough() /* useAccelerateInterpolator */);
} else {
// Didn't move enough to dismiss or cover, snap to the gear
snapToGear(animView, velocity);
@@ -3609,7 +3612,8 @@
private void dismissOrSnapBack(View animView, float velocity, MotionEvent ev) {
if (isDismissGesture(ev)) {
- dismissChild(animView, swipedFastEnough() ? velocity : 0f);
+ dismissChild(animView, velocity,
+ !swipedFastEnough() /* useAccelerateInterpolator */);
} else {
snapChild(animView, 0 /* leftTarget */, velocity);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 4c94fe9..c7333c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -368,7 +368,7 @@
childViewState.location = StackViewState.LOCATION_UNKNOWN;
paddingAfterChild = getPaddingAfterChild(algorithmState, child);
int childHeight = getMaxAllowedChildHeight(child);
- int minHeight = child.getMinHeight();
+ int collapsedHeight = child.getCollapsedHeight();
childViewState.yTranslation = currentYPosition;
if (i == 0) {
updateFirstChildHeight(child, childViewState, childHeight, ambientState);
@@ -384,7 +384,7 @@
// According to the regular scroll view we are fully translated out of the
// bottom of the screen so we are fully in the bottom stack
updateStateForChildFullyInBottomStack(algorithmState,
- bottomStackStart, childViewState, minHeight, ambientState, child);
+ bottomStackStart, childViewState, collapsedHeight, ambientState, child);
} else {
// According to the regular scroll view we are currently translating out of /
// into the bottom of the screen
@@ -475,17 +475,17 @@
float newTranslation = Math.max(ambientState.getTopPadding()
+ ambientState.getStackTranslation(), childState.yTranslation);
childState.height = (int) Math.max(childState.height - (newTranslation
- - childState.yTranslation), row.getMinHeight());
+ - childState.yTranslation), row.getCollapsedHeight());
childState.yTranslation = newTranslation;
}
private void clampHunToMaxTranslation(AmbientState ambientState, ExpandableNotificationRow row,
StackViewState childState) {
float newTranslation;
- float bottomPosition = ambientState.getMaxHeadsUpTranslation() - row.getMinHeight();
+ float bottomPosition = ambientState.getMaxHeadsUpTranslation() - row.getCollapsedHeight();
newTranslation = Math.min(childState.yTranslation, bottomPosition);
childState.height = (int) Math.max(childState.height
- - (childState.yTranslation - newTranslation), row.getMinHeight());
+ - (childState.yTranslation - newTranslation), row.getCollapsedHeight());
childState.yTranslation = newTranslation;
}
@@ -534,10 +534,10 @@
float offset = mBottomStackIndentationFunctor.getValue(algorithmState.partialInBottom);
algorithmState.itemsInBottomStack += algorithmState.partialInBottom;
int newHeight = childHeight;
- if (childHeight > child.getMinHeight()) {
+ if (childHeight > child.getCollapsedHeight()) {
newHeight = (int) Math.max(Math.min(transitioningPositionStart + offset -
getPaddingAfterChild(algorithmState, child) - currentYPosition, childHeight),
- child.getMinHeight());
+ child.getCollapsedHeight());
childViewState.height = newHeight;
}
childViewState.yTranslation = transitioningPositionStart + offset - newHeight
@@ -547,7 +547,7 @@
private void updateStateForChildFullyInBottomStack(StackScrollAlgorithmState algorithmState,
float transitioningPositionStart, StackViewState childViewState,
- int minHeight, AmbientState ambientState, ExpandableView child) {
+ int collapsedHeight, AmbientState ambientState, ExpandableView child) {
float currentYPosition;
algorithmState.itemsInBottomStack += 1.0f;
if (algorithmState.itemsInBottomStack < MAX_ITEMS_IN_BOTTOM_STACK) {
@@ -568,16 +568,14 @@
childViewState.location = StackViewState.LOCATION_BOTTOM_STACK_HIDDEN;
currentYPosition = ambientState.getInnerHeight();
}
- childViewState.height = minHeight;
- childViewState.yTranslation = currentYPosition - minHeight;
+ childViewState.height = collapsedHeight;
+ childViewState.yTranslation = currentYPosition - collapsedHeight;
}
/**
* Update the height of the first child i.e clamp it to the bottom stack
*
- *
-
* @param child the child to update
* @param childViewState the viewstate of the child
* @param childHeight the height of the child
@@ -591,7 +589,7 @@
mBottomStackSlowDownLength + ambientState.getScrollY();
// Collapse and expand the first child while the shade is being expanded
childViewState.height = (int) Math.max(Math.min(bottomPeekStart, (float) childHeight),
- child.getMinHeight());
+ child.getCollapsedHeight());
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java
index 8c945f9..ae2856c 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java
@@ -43,7 +43,6 @@
public static final String EXTRA_SHOW_NIGHT_MODE = "show_night_mode";
private static final CharSequence KEY_AUTO = "auto";
- private static final CharSequence KEY_DARK_THEME = "dark_theme";
private static final CharSequence KEY_ADJUST_TINT = "adjust_tint";
private static final CharSequence KEY_ADJUST_BRIGHTNESS = "adjust_brightness";
@@ -51,7 +50,6 @@
private NightModeController mNightModeController;
private SwitchPreference mAutoSwitch;
- private SwitchPreference mDarkTheme;
private SwitchPreference mAdjustTint;
private SwitchPreference mAdjustBrightness;
private UiModeManager mUiModeManager;
@@ -79,8 +77,6 @@
addPreferencesFromResource(R.xml.night_mode);
mAutoSwitch = (SwitchPreference) findPreference(KEY_AUTO);
mAutoSwitch.setOnPreferenceChangeListener(this);
- mDarkTheme = (SwitchPreference) findPreference(KEY_DARK_THEME);
- mDarkTheme.setOnPreferenceChangeListener(this);
mAdjustTint = (SwitchPreference) findPreference(KEY_ADJUST_TINT);
mAdjustTint.setOnPreferenceChangeListener(this);
mAdjustBrightness = (SwitchPreference) findPreference(KEY_ADJUST_BRIGHTNESS);
@@ -111,7 +107,6 @@
mNightModeController.addListener(this);
TunerService.get(getContext()).addTunable(this, Secure.BRIGHTNESS_USE_TWILIGHT,
NightModeController.NIGHT_MODE_ADJUST_TINT);
- mDarkTheme.setChecked(mUiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_AUTO);
calculateDisabled();
}
@@ -129,12 +124,6 @@
if (mAutoSwitch == preference) {
MetricsLogger.action(getContext(), MetricsEvent.ACTION_TUNER_NIGHT_MODE_AUTO, value);
mNightModeController.setAuto(value);
- } else if (mDarkTheme == preference) {
- MetricsLogger.action(getContext(),
- MetricsEvent.ACTION_TUNER_NIGHT_MODE_ADJUST_DARK_THEME, value);
- mUiModeManager.setNightMode(value ? UiModeManager.MODE_NIGHT_AUTO
- : UiModeManager.MODE_NIGHT_NO);
- postCalculateDisabled();
} else if (mAdjustTint == preference) {
MetricsLogger.action(getContext(),
MetricsEvent.ACTION_TUNER_NIGHT_MODE_ADJUST_TINT, value);
@@ -163,19 +152,15 @@
}
private void calculateDisabled() {
- int enabledCount = (mDarkTheme.isChecked() ? 1 : 0)
- + (mAdjustTint.isChecked() ? 1 : 0)
+ int enabledCount = (mAdjustTint.isChecked() ? 1 : 0)
+ (mAdjustBrightness.isChecked() ? 1 : 0);
if (enabledCount == 1) {
- if (mDarkTheme.isChecked()) {
- mDarkTheme.setEnabled(false);
- } else if (mAdjustTint.isChecked()) {
+ if (mAdjustTint.isChecked()) {
mAdjustTint.setEnabled(false);
} else {
mAdjustBrightness.setEnabled(false);
}
} else {
- mDarkTheme.setEnabled(true);
mAdjustTint.setEnabled(true);
mAdjustBrightness.setEnabled(true);
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java
index 15ad1f1..3f87611 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java
@@ -16,11 +16,12 @@
package com.android.systemui.tv.pip;
-import android.app.Activity;
import android.content.Context;
import android.media.session.MediaController;
import android.media.session.PlaybackState;
import android.view.View;
+import android.view.Gravity;
+import android.view.LayoutInflater;
import android.view.View.OnFocusChangeListener;
import android.widget.ImageView;
import android.widget.TextView;
@@ -40,28 +41,29 @@
/**
* A view containing PIP controls including fullscreen, close, and media controls.
*/
-public class PipControlsView extends LinearLayout implements PipManager.Listener {
+public class PipControlsView extends LinearLayout {
/**
* An interface to listen user action.
*/
- public interface Listener {
+ public abstract static interface Listener {
/**
* Called when an user clicks close PIP button.
*/
- void onClosed();
- }
+ public abstract void onClosed();
+ };
- private final PipManager mPipManager = PipManager.getInstance();
private MediaController mMediaController;
- private Listener mListener;
- private View mFullButtonView;
- private View mFullDescriptionView;
- private View mPlayPauseView;
- private ImageView mPlayPauseButtonImageView;
- private TextView mPlayPauseDescriptionTextView;
- private View mCloseButtonView;
- private View mCloseDescriptionView;
+ final PipManager mPipManager = PipManager.getInstance();
+ Listener mListener;
+
+ View mFullButtonView;
+ View mFullDescriptionView;
+ View mPlayPauseView;
+ ImageView mPlayPauseButtonImageView;
+ TextView mPlayPauseDescriptionTextView;
+ View mCloseButtonView;
+ View mCloseDescriptionView;
private boolean mHasFocus;
private OnFocusChangeListener mOnChildFocusChangeListener;
@@ -73,6 +75,13 @@
}
};
+ private PipManager.MediaListener mPipMediaListener = new PipManager.MediaListener() {
+ @Override
+ public void onMediaControllerChanged() {
+ updateMediaController();
+ }
+ };
+
public PipControlsView(Context context) {
this(context, null, 0, 0);
}
@@ -87,6 +96,12 @@
public PipControlsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ LayoutInflater inflater = (LayoutInflater) getContext()
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(R.layout.tv_pip_controls, this);
+
+ setOrientation(LinearLayout.HORIZONTAL);
+ setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL);
}
@Override
@@ -161,13 +176,13 @@
public void onAttachedToWindow() {
super.onAttachedToWindow();
updateMediaController();
- mPipManager.addListener(this);
+ mPipManager.addMediaListener(mPipMediaListener);
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
- mPipManager.removeListener(this);
+ mPipManager.removeMediaListener(mPipMediaListener);
if (mMediaController != null) {
mMediaController.unregisterCallback(mMediaControllerCallback);
}
@@ -230,24 +245,4 @@
public void setListener(Listener listener) {
mListener = listener;
}
-
- @Override
- public void onPipEntered() { }
-
- @Override
- public void onPipActivityClosed() { }
-
- @Override
- public void onShowPipMenu() { }
-
- @Override
- public void onMoveToFullscreen() { }
-
- @Override
- public void onMediaControllerChanged() {
- updateMediaController();
- }
-
- @Override
- public void onPipResizeAboutToStart() { }
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index 68e0883..b5c1f57 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -62,9 +62,27 @@
private static final int MAX_RUNNING_TASKS_COUNT = 10;
+ /**
+ * State when there's no PIP.
+ */
public static final int STATE_NO_PIP = 0;
+ /**
+ * State when PIP is shown with an overlay message on top of it.
+ * This is used as default PIP state.
+ */
public static final int STATE_PIP_OVERLAY = 1;
+ /**
+ * State when PIP menu dialog is shown.
+ */
public static final int STATE_PIP_MENU = 2;
+ /**
+ * State when PIP is shown in Recents.
+ */
+ public static final int STATE_PIP_RECENTS = 3;
+ /**
+ * State when PIP is shown in Recents and it's focused to allow an user to control.
+ */
+ public static final int STATE_PIP_RECENTS_FOCUSED = 4;
private static final int TASK_ID_NO_PIP = -1;
private static final int INVALID_RESOURCE_TYPE = -1;
@@ -90,11 +108,13 @@
private int mSuspendPipResizingReason;
private Context mContext;
+ private PipRecentsOverlayManager mPipRecentsOverlayManager;
private IActivityManager mActivityManager;
private MediaSessionManager mMediaSessionManager;
private int mState = STATE_NO_PIP;
private final Handler mHandler = new Handler();
private List<Listener> mListeners = new ArrayList<>();
+ private List<MediaListener> mMediaListeners = new ArrayList<>();
private Rect mCurrentPipBounds;
private Rect mPipBounds;
private Rect mMenuModePipBounds;
@@ -107,9 +127,6 @@
private MediaController mPipMediaController;
private boolean mOnboardingShown;
- private boolean mIsRecentsShown;
- private boolean mIsPipFocusedInRecent;
-
private final Runnable mResizePinnedStackRunnable = new Runnable() {
@Override
public void run() {
@@ -178,6 +195,7 @@
mOnboardingShown = Prefs.getBoolean(
mContext, TV_PICTURE_IN_PICTURE_ONBOARDING_SHOWN, false);
+ mPipRecentsOverlayManager = new PipRecentsOverlayManager(context);
mMediaSessionManager =
(MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
}
@@ -231,7 +249,7 @@
/**
* Moves the PIPed activity to the fullscreen and closes PIP system UI.
*/
- public void movePipToFullscreen() {
+ void movePipToFullscreen() {
mState = STATE_NO_PIP;
mPipTaskId = TASK_ID_NO_PIP;
for (int i = mListeners.size() - 1; i >= 0; --i) {
@@ -247,8 +265,11 @@
*/
private void showPipOverlay() {
if (DEBUG) Log.d(TAG, "showPipOverlay()");
- mState = STATE_PIP_OVERLAY;
- PipOverlayActivity.showPipOverlay(mContext);
+ Intent intent = new Intent(mContext, PipOverlayActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchStackId(PINNED_STACK_ID);
+ mContext.startActivity(intent, options.toBundle());
}
/**
@@ -279,8 +300,10 @@
* Resize the Pip to the appropriate size for the input state.
* @param state In Pip state also used to determine the new size for the Pip.
*/
- public void resizePinnedStack(int state) {
+ void resizePinnedStack(int state) {
if (DEBUG) Log.d(TAG, "resizePinnedStack() state=" + state);
+ boolean wasRecentsShown =
+ (mState == STATE_PIP_RECENTS || mState == STATE_PIP_RECENTS_FOCUSED);
mState = state;
for (int i = mListeners.size() - 1; i >= 0; --i) {
mListeners.get(i).onPipResizeAboutToStart();
@@ -291,7 +314,6 @@
mSuspendPipResizingReason);
return;
}
- int animationDurationMs = -1;
switch (mState) {
case STATE_NO_PIP:
mCurrentPipBounds = null;
@@ -300,25 +322,24 @@
mCurrentPipBounds = mMenuModePipBounds;
break;
case STATE_PIP_OVERLAY:
- if (mIsRecentsShown) {
- if (mCurrentPipBounds == mRecentsFocusedPipBounds
- || mCurrentPipBounds == mRecentsFocusedPipBounds) {
- animationDurationMs = mRecentsFocusChangedAnimationDurationMs;
- }
- if (mIsPipFocusedInRecent) {
- mCurrentPipBounds = mRecentsFocusedPipBounds;
- } else {
- mCurrentPipBounds = mRecentsPipBounds;
- }
- } else {
- mCurrentPipBounds = mPipBounds;
- }
+ mCurrentPipBounds = mPipBounds;
+ break;
+ case STATE_PIP_RECENTS:
+ mCurrentPipBounds = mRecentsPipBounds;
+ break;
+ case STATE_PIP_RECENTS_FOCUSED:
+ mCurrentPipBounds = mRecentsFocusedPipBounds;
break;
default:
mCurrentPipBounds = mPipBounds;
break;
}
try {
+ int animationDurationMs = -1;
+ if (wasRecentsShown
+ && (mState == STATE_PIP_RECENTS || mState == STATE_PIP_RECENTS_FOCUSED)) {
+ animationDurationMs = mRecentsFocusChangedAnimationDurationMs;
+ }
mActivityManager.resizeStack(PINNED_STACK_ID, mCurrentPipBounds,
true, true, true, animationDurationMs);
} catch (RemoteException e) {
@@ -327,67 +348,18 @@
}
/**
- * Returns the current PIP bound for activities to sync their UI with PIP.
+ * Returns the default PIP bound.
*/
public Rect getPipBounds() {
- return mCurrentPipBounds;
+ return mPipBounds;
}
/**
- * Called when Recents is started.
- * PIPed activity will be resized accordingly and overlay will show available buttons.
+ * Returns the focused PIP bound while Recents is shown.
+ * This is used to place PIP controls in Recents.
*/
- public void onRecentsStarted() {
- mIsRecentsShown = true;
- mIsPipFocusedInRecent = false;
- if (mState == STATE_NO_PIP) {
- return;
- }
- resizePinnedStack(STATE_PIP_OVERLAY);
- }
-
- /**
- * Called when Recents is stopped.
- * PIPed activity will be resized accordingly and overlay will hide available buttons.
- */
- public void onRecentsStopped() {
- mIsRecentsShown = false;
- mIsPipFocusedInRecent = false;
- if (mState == STATE_NO_PIP) {
- return;
- }
- resizePinnedStack(STATE_PIP_OVERLAY);
- }
-
- /**
- * Returns {@code true} if recents is shown.
- */
- boolean isRecentsShown() {
- return mIsRecentsShown;
- }
-
- /**
- * Called when the PIP view in {@link com.android.systemui.recents.tv.RecentsTvActivity}
- * is focused.
- * This only resizes pinned stack so it looks like it's in Recents.
- * This should be called only by {@link com.android.systemui.recents.tv.RecentsTvActivity}.
- */
- public void onPipViewFocusChangedInRecents(boolean hasFocus) {
- mIsPipFocusedInRecent = hasFocus;
- if (mState != STATE_PIP_OVERLAY) {
- Log.w(TAG, "There is no pinned stack to handle focus change.");
- return;
- }
- resizePinnedStack(STATE_PIP_OVERLAY);
- }
-
- /**
- * Returns {@code true} if the PIP view in
- * {@link com.android.systemui.recents.tv.RecentsTvActivity} is focused in Recents.
- * This API is valid only when {@link isRecentsShown()} returns {@code true}.
- */
- boolean isPipViewFocusdInRecents() {
- return mIsPipFocusedInRecent;
+ public Rect getRecentsFocusedPipBounds() {
+ return mRecentsFocusedPipBounds;
}
/**
@@ -396,6 +368,10 @@
*/
private void showPipMenu() {
if (DEBUG) Log.d(TAG, "showPipMenu()");
+ if (mPipRecentsOverlayManager.isRecentsShown()) {
+ if (DEBUG) Log.d(TAG, "Ignore showing PIP menu");
+ return;
+ }
mState = STATE_PIP_MENU;
for (int i = mListeners.size() - 1; i >= 0; --i) {
mListeners.get(i).onShowPipMenu();
@@ -405,14 +381,34 @@
mContext.startActivity(intent);
}
+ /**
+ * Adds a {@link Listener} to PipManager.
+ */
public void addListener(Listener listener) {
mListeners.add(listener);
}
+ /**
+ * Removes a {@link Listener} from PipManager.
+ */
public void removeListener(Listener listener) {
mListeners.remove(listener);
}
+ /**
+ * Adds a {@link MediaListener} to PipManager.
+ */
+ public void addMediaListener(MediaListener listener) {
+ mMediaListeners.add(listener);
+ }
+
+ /**
+ * Removes a {@link MediaListener} from PipManager.
+ */
+ public void removeMediaListener(MediaListener listener) {
+ mMediaListeners.remove(listener);
+ }
+
private void launchPipOnboardingActivityIfNeeded() {
if (DEBUG_FORCE_ONBOARDING || !mOnboardingShown) {
mOnboardingShown = true;
@@ -485,8 +481,8 @@
}
if (mPipMediaController != mediaController) {
mPipMediaController = mediaController;
- for (int i = mListeners.size() - 1; i >= 0; i--) {
- mListeners.get(i).onMediaControllerChanged();
+ for (int i = mMediaListeners.size() - 1; i >= 0; i--) {
+ mMediaListeners.get(i).onMediaControllerChanged();
}
if (mPipMediaController == null) {
mHandler.postDelayed(mClosePipRunnable,
@@ -530,7 +526,7 @@
return PLAYBACK_STATE_UNAVAILABLE;
}
- TaskStackListener mTaskStackListener = new TaskStackListener() {
+ private TaskStackListener mTaskStackListener = new TaskStackListener() {
@Override
public void onTaskStackChanged() {
if (mState != STATE_NO_PIP) {
@@ -582,10 +578,10 @@
mMediaSessionManager.addOnActiveSessionsChangedListener(
mActiveMediaSessionListener, null);
updateMediaController(mMediaSessionManager.getActiveSessions(null));
- if (mIsRecentsShown) {
+ if (mPipRecentsOverlayManager.isRecentsShown()) {
// If an activity becomes PIPed again after the fullscreen, the Recents is shown
// behind so we need to resize the pinned stack and show the correct overlay.
- resizePinnedStack(STATE_PIP_OVERLAY);
+ resizePinnedStack(STATE_PIP_RECENTS);
}
for (int i = mListeners.size() - 1; i >= 0; i--) {
mListeners.get(i).onPipEntered();
@@ -604,7 +600,18 @@
if (DEBUG) Log.d(TAG, "onPinnedStackAnimationEnded()");
switch (mState) {
case STATE_PIP_OVERLAY:
- showPipOverlay();
+ if (!mPipRecentsOverlayManager.isRecentsShown()) {
+ showPipOverlay();
+ break;
+ } else {
+ // This happens only if an activity is PIPed after the Recents is shown.
+ // See {@link PipRecentsOverlayManager.requestFocus} for more details.
+ resizePinnedStack(mState);
+ break;
+ }
+ case STATE_PIP_RECENTS:
+ case STATE_PIP_RECENTS_FOCUSED:
+ mPipRecentsOverlayManager.addPipRecentsOverlayView();
break;
case STATE_PIP_MENU:
showPipMenu();
@@ -621,7 +628,7 @@
* Invoked when an activity is pinned and PIP manager is set corresponding information.
* Classes must use this instead of {@link android.app.ITaskStackListener.onActivityPinned}
* because there's no guarantee for the PIP manager be return relavent information
- * correctly. (e.g. {@link isPipShown}, {@link getPipBounds})
+ * correctly. (e.g. {@link isPipShown}).
*/
void onPipEntered();
/** Invoked when a PIPed activity is closed. */
@@ -632,6 +639,12 @@
void onMoveToFullscreen();
/** Invoked when we are above to start resizing the Pip. */
void onPipResizeAboutToStart();
+ }
+
+ /**
+ * A listener interface to receive change in PIP's media controller
+ */
+ public interface MediaListener {
/** Invoked when the MediaController on PIPed activity is changed. */
void onMediaControllerChanged();
}
@@ -645,4 +658,11 @@
}
return sPipManager;
}
+
+ /**
+ * Gets an instance of {@link PipRecentsOverlayManager}.
+ */
+ public PipRecentsOverlayManager getPipRecentsOverlayManager() {
+ return mPipRecentsOverlayManager;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
index ea9275f..c54e73a 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
@@ -20,12 +20,6 @@
import android.os.Bundle;
import com.android.systemui.R;
-import com.android.systemui.SystemUI;
-import com.android.systemui.SystemUIApplication;
-import com.android.systemui.recents.Recents;
-
-import static android.content.pm.PackageManager.FEATURE_LEANBACK;
-import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
/**
* Activity to show the PIP menu to control PIP.
@@ -36,7 +30,6 @@
private final PipManager mPipManager = PipManager.getInstance();
private PipControlsView mPipControlsView;
- private boolean mPipMovedToFullscreen;
@Override
protected void onCreate(Bundle bundle) {
@@ -47,17 +40,10 @@
mPipControlsView = (PipControlsView) findViewById(R.id.pip_controls);
}
- private void restorePipAndFinish() {
- if (!mPipMovedToFullscreen) {
- mPipManager.resizePinnedStack(PipManager.STATE_PIP_OVERLAY);
- }
- finish();
- }
-
@Override
public void onPause() {
super.onPause();
- restorePipAndFinish();
+ finish();
}
@Override
@@ -69,11 +55,6 @@
}
@Override
- public void onBackPressed() {
- restorePipAndFinish();
- }
-
- @Override
public void onPipEntered() { }
@Override
@@ -86,31 +67,13 @@
@Override
public void onMoveToFullscreen() {
- mPipMovedToFullscreen = true;
finish();
}
@Override
- public void onMediaControllerChanged() { }
-
- @Override
public void onPipResizeAboutToStart() {
finish();
mPipManager.suspendPipResizing(
PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
}
-
- @Override
- public void finish() {
- super.finish();
- if (mPipManager.isRecentsShown() && !mPipMovedToFullscreen) {
- SystemUI[] services = ((SystemUIApplication) getApplication()).getServices();
- for (int i = services.length - 1; i >= 0; i--) {
- if (services[i] instanceof Recents) {
- ((Recents) services[i]).showRecents(false, null);
- break;
- }
- }
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
index 79daf3d..86ceff4 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
@@ -86,7 +86,4 @@
@Override
public void onPipResizeAboutToStart() { }
-
- @Override
- public void onMediaControllerChanged() { }
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
index 12cb4cd..5472ad6 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
@@ -35,14 +35,6 @@
public class PipOverlayActivity extends Activity implements PipManager.Listener {
private static final long SHOW_GUIDE_OVERLAY_VIEW_DURATION_MS = 4000;
- /**
- * The single instance of PipOverlayActivity to prevent it from restarting.
- * Note that {@link PipManager} moves the PIPed activity to fullscreen if the activity is
- * restarted. It's because the activity may be started by the Launcher or an intent again,
- * but we don't want do so for the PipOverlayActivity.
- */
- private static PipOverlayActivity sPipOverlayActivity;
-
private final PipManager mPipManager = PipManager.getInstance();
private final Handler mHandler = new Handler();
private View mGuideOverlayView;
@@ -54,47 +46,17 @@
}
};
- /**
- * Launches the PIP overlay. This should be only called on the main thread.
- */
- public static void showPipOverlay(Context context) {
- if (sPipOverlayActivity == null) {
- Intent intent = new Intent(context, PipOverlayActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- final ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchStackId(PINNED_STACK_ID);
- context.startActivity(intent, options.toBundle());
- }
- }
-
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.tv_pip_overlay);
mGuideOverlayView = findViewById(R.id.guide_overlay);
- mGuideButtonsView = findViewById(R.id.guide_buttons);
- mGuideButtonPlayPauseImageView = (ImageView) findViewById(R.id.guide_button_play_pause);
mPipManager.addListener(this);
-
- sPipOverlayActivity = this;
}
@Override
protected void onResume() {
super.onResume();
- // TODO: Implement animation for this
- if (mPipManager.isRecentsShown()) {
- mGuideOverlayView.setVisibility(View.GONE);
- if (mPipManager.isPipViewFocusdInRecents()) {
- mGuideButtonsView.setVisibility(View.GONE);
- } else {
- mGuideButtonsView.setVisibility(View.VISIBLE);
- updateGuideButtonsView();
- }
- } else {
- mGuideOverlayView.setVisibility(View.VISIBLE);
- mGuideButtonsView.setVisibility(View.GONE);
- }
mHandler.removeCallbacks(mHideGuideOverlayRunnable);
mHandler.postDelayed(mHideGuideOverlayRunnable, SHOW_GUIDE_OVERLAY_VIEW_DURATION_MS);
}
@@ -109,7 +71,6 @@
@Override
protected void onDestroy() {
super.onDestroy();
- sPipOverlayActivity = null;
mHandler.removeCallbacksAndMessages(null);
mPipManager.removeListener(this);
mPipManager.resumePipResizing(
@@ -140,32 +101,4 @@
mPipManager.suspendPipResizing(
PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_OVERLAY_ACTIVITY_FINISH);
}
-
- @Override
- public void onMediaControllerChanged() {
- updateGuideButtonsView();
- }
-
- @Override
- public void finish() {
- sPipOverlayActivity = null;
- super.finish();
- }
-
- private void updateGuideButtonsView() {
- switch (mPipManager.getPlaybackState()) {
- case PipManager.PLAYBACK_STATE_PLAYING:
- mGuideButtonPlayPauseImageView.setVisibility(View.VISIBLE);
- mGuideButtonPlayPauseImageView.setImageResource(R.drawable.ic_pause_white_24dp);
- break;
- case PipManager.PLAYBACK_STATE_PAUSED:
- mGuideButtonPlayPauseImageView.setVisibility(View.VISIBLE);
- mGuideButtonPlayPauseImageView.setImageResource(
- R.drawable.ic_play_arrow_white_24dp);
- break;
- case PipManager.PLAYBACK_STATE_UNAVAILABLE:
- mGuideButtonPlayPauseImageView.setVisibility(View.GONE);
- break;
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java
new file mode 100644
index 0000000..8b8c105
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2016 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.systemui.tv.pip;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorSet;
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.View.OnFocusChangeListener;
+
+import com.android.systemui.R;
+
+import static com.android.systemui.tv.pip.PipManager.PLAYBACK_STATE_PLAYING;
+import static com.android.systemui.tv.pip.PipManager.PLAYBACK_STATE_PAUSED;
+import static com.android.systemui.tv.pip.PipManager.PLAYBACK_STATE_UNAVAILABLE;
+
+/**
+ * An extended version of {@link PipControlsView} that supports animation in Recents.
+ */
+public class PipRecentsControlsView extends PipControlsView {
+ /**
+ * An interface to listen user action.
+ */
+ public interface Listener extends PipControlsView.Listener {
+ /**
+ * Called when an user presses BACK key and up.
+ */
+ abstract void onBackPressed();
+ }
+
+ private AnimatorSet mFocusGainAnimatorSet;
+ private AnimatorSet mFocusLoseAnimatorSet;
+
+ public PipRecentsControlsView(Context context) {
+ this(context, null, 0, 0);
+ }
+
+ public PipRecentsControlsView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0, 0);
+ }
+
+ public PipRecentsControlsView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public PipRecentsControlsView(
+ Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ public void onFinishInflate() {
+ super.onFinishInflate();
+
+ int buttonsFocusGainAnim = R.anim.tv_pip_controls_buttons_in_recents_focus_gain_animation;
+ int textFocusGainAnim = R.anim.tv_pip_controls_text_in_recents_focus_gain_animation;
+ mFocusGainAnimatorSet = new AnimatorSet();
+ mFocusGainAnimatorSet.playTogether(
+ loadAnimator(this, R.anim.tv_pip_controls_in_recents_focus_gain_animation),
+ loadAnimator(mFullButtonView,buttonsFocusGainAnim),
+ loadAnimator(mPlayPauseButtonImageView, buttonsFocusGainAnim),
+ loadAnimator(mCloseButtonView, buttonsFocusGainAnim),
+ loadAnimator(mFullDescriptionView, textFocusGainAnim),
+ loadAnimator(mPlayPauseDescriptionTextView, textFocusGainAnim),
+ loadAnimator(mCloseDescriptionView, textFocusGainAnim));
+
+ int buttonsFocusLoseAnim = R.anim.tv_pip_controls_buttons_in_recents_focus_lose_animation;
+ int textFocusLoseAnim = R.anim.tv_pip_controls_text_in_recents_focus_lose_animation;
+ mFocusLoseAnimatorSet = new AnimatorSet();
+ mFocusLoseAnimatorSet.playTogether(
+ loadAnimator(this, R.anim.tv_pip_controls_in_recents_focus_lose_animation),
+ loadAnimator(mFullButtonView, buttonsFocusLoseAnim),
+ loadAnimator(mPlayPauseButtonImageView, buttonsFocusLoseAnim),
+ loadAnimator(mCloseButtonView, buttonsFocusLoseAnim),
+ loadAnimator(mFullDescriptionView, textFocusLoseAnim),
+ loadAnimator(mPlayPauseDescriptionTextView, textFocusLoseAnim),
+ loadAnimator(mCloseDescriptionView, textFocusLoseAnim));
+
+ Rect pipBounds = mPipManager.getRecentsFocusedPipBounds();
+ int pipControlsMarginTop = getContext().getResources().getDimensionPixelSize(
+ R.dimen.recents_tv_pip_controls_margin_top);
+ setPadding(0, pipBounds.bottom + pipControlsMarginTop, 0, 0);
+ }
+
+ private Animator loadAnimator(View view, int animatorResId) {
+ Animator animator = AnimatorInflater.loadAnimator(getContext(), animatorResId);
+ animator.setTarget(view);
+ return animator;
+ }
+
+ /**
+ * Starts focus gaining animation.
+ */
+ public void startFocusGainAnimation() {
+ if (mFocusLoseAnimatorSet.isStarted()) {
+ mFocusLoseAnimatorSet.cancel();
+ }
+ mFocusGainAnimatorSet.start();
+ }
+
+ /**
+ * Starts focus losing animation.
+ */
+ public void startFocusLoseAnimation() {
+ if (mFocusGainAnimatorSet.isStarted()) {
+ mFocusGainAnimatorSet.cancel();
+ }
+ mFocusLoseAnimatorSet.start();
+ }
+
+ /**
+ * Resets the view to the initial state. (i.e. end of the focus gain)
+ */
+ public void reset() {
+ if (mFocusGainAnimatorSet.isStarted()) {
+ mFocusGainAnimatorSet.cancel();
+ }
+ if (mFocusLoseAnimatorSet.isStarted()) {
+ mFocusLoseAnimatorSet.cancel();
+ }
+
+ // Reset to initial state (i.e. end of focused)
+ requestFocus();
+ setTranslationY(0);
+ setScaleXY(mFullButtonView, 1);
+ setScaleXY(mPlayPauseButtonImageView, 1);
+ setScaleXY(mCloseButtonView, 1);
+ mFullDescriptionView.setAlpha(1);
+ mPlayPauseDescriptionTextView.setAlpha(1);
+ mCloseDescriptionView.setAlpha(1);
+ }
+
+ private void setScaleXY(View view, float scale) {
+ view.setScaleX(scale);
+ view.setScaleY(scale);
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (!event.isCanceled()
+ && event.getKeyCode() == KeyEvent.KEYCODE_BACK
+ && event.getAction() == KeyEvent.ACTION_UP) {
+ if (mListener != null) {
+ ((PipRecentsControlsView.Listener) mListener).onBackPressed();
+ }
+ return true;
+ }
+ return super.dispatchKeyEvent(event);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
new file mode 100644
index 0000000..b90b727
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2016 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.systemui.tv.pip;
+
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorSet;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager.LayoutParams;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+
+import static com.android.systemui.tv.pip.PipManager.STATE_PIP_OVERLAY;
+import static com.android.systemui.tv.pip.PipManager.STATE_PIP_RECENTS;
+import static com.android.systemui.tv.pip.PipManager.STATE_PIP_RECENTS_FOCUSED;
+
+public class PipRecentsOverlayManager {
+ private static final String TAG = "PipRecentsOverlayManager";
+
+ public interface Callback {
+ void onClosed();
+ void onBackPressed();
+ void onRecentsFocused();
+ }
+
+ private final PipManager mPipManager = PipManager.getInstance();
+ private final WindowManager mWindowManager;
+ private final View mOverlayView;
+ private final PipRecentsControlsView mPipControlsView;
+ private final View mRecentsView;
+
+ private final LayoutParams mPipRecentsControlsViewLayoutParams;
+ private final LayoutParams mPipRecentsControlsViewFocusedLayoutParams;
+
+ private boolean mIsPipRecentsOverlayShown;
+ private boolean mIsRecentsShown;
+ private boolean mIsPipFocusedInRecent;
+ private Callback mCallback;
+ private PipRecentsControlsView.Listener mPipControlsViewListener =
+ new PipRecentsControlsView.Listener() {
+ @Override
+ public void onClosed() {
+ if (mCallback != null) {
+ mCallback.onClosed();
+ }
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (mCallback != null) {
+ mCallback.onBackPressed();
+ }
+ }
+ };
+
+ PipRecentsOverlayManager(Context context) {
+ mWindowManager = (WindowManager) context.getSystemService(WindowManager.class);
+
+ LayoutInflater inflater = (LayoutInflater) context
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mOverlayView = inflater.inflate(R.layout.tv_pip_recents_overlay, null);
+ mPipControlsView = (PipRecentsControlsView) mOverlayView.findViewById(R.id.pip_controls);
+ mRecentsView = mOverlayView.findViewById(R.id.recents);
+ mRecentsView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (hasFocus) {
+ clearFocus();
+ }
+ }
+ });
+
+ mPipRecentsControlsViewLayoutParams = new WindowManager.LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
+ LayoutParams.TYPE_SYSTEM_DIALOG,
+ LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCHABLE,
+ PixelFormat.TRANSLUCENT);
+ mPipRecentsControlsViewFocusedLayoutParams = new WindowManager.LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
+ LayoutParams.TYPE_SYSTEM_DIALOG,
+ 0,
+ PixelFormat.TRANSLUCENT);
+ }
+
+ /**
+ * Add Recents overlay view.
+ * This is expected to be called after the PIP animation is over.
+ */
+ void addPipRecentsOverlayView() {
+ if (mIsPipRecentsOverlayShown) {
+ return;
+ }
+ mIsPipRecentsOverlayShown = true;
+ mIsPipFocusedInRecent = true;
+ mPipControlsView.reset();
+ mWindowManager.addView(mOverlayView, mPipRecentsControlsViewFocusedLayoutParams);
+ }
+
+ /**
+ * Remove Recents overlay view.
+ * This should be called when Recents or PIP is closed.
+ */
+ public void removePipRecentsOverlayView() {
+ if (!mIsPipRecentsOverlayShown) {
+ return;
+ }
+ mWindowManager.removeView(mOverlayView);
+ mIsPipRecentsOverlayShown = false;
+ }
+
+ /**
+ * Request focus to the PIP Recents overlay.
+ * Called when the PIP view in {@link com.android.systemui.recents.tv.RecentsTvActivity}
+ * is focused.
+ * This should be called only by {@link com.android.systemui.recents.tv.RecentsTvActivity}.
+ * @param hasRecentsFocusable {@code true} if Recents can have focus. (i.e. Has a recent task)
+ */
+ public void requestFocus(boolean hasRecentsFocusable) {
+ if (!mIsRecentsShown || mIsPipFocusedInRecent) {
+ return;
+ }
+ mIsPipFocusedInRecent = true;
+ mPipManager.resizePinnedStack(STATE_PIP_RECENTS_FOCUSED);
+
+ mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewFocusedLayoutParams);
+ mPipControlsView.requestFocus();
+ mPipControlsView.startFocusGainAnimation();
+ mRecentsView.setVisibility(hasRecentsFocusable ? View.VISIBLE : View.GONE);
+ }
+
+ /**
+ * Request focus to the PIP Recents overlay.
+ * Called when the PIP view in {@link com.android.systemui.recents.tv.RecentsTvActivity}
+ * is focused.
+ * This should be called only by {@link com.android.systemui.recents.tv.RecentsTvActivity}.
+ */
+ private void clearFocus() {
+ if (!mIsRecentsShown || !mIsPipFocusedInRecent) {
+ return;
+ }
+ mIsPipFocusedInRecent = false;
+ mPipManager.resizePinnedStack(STATE_PIP_RECENTS);
+ mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewLayoutParams);
+ mPipControlsView.startFocusLoseAnimation();
+ if (mCallback != null) {
+ mCallback.onRecentsFocused();
+ }
+ }
+
+ public void setCallback(Callback listener) {
+ mCallback = listener;
+ mPipControlsView.setListener(mCallback != null ? mPipControlsViewListener : null);
+ }
+
+ /**
+ * Called when Recents is resumed.
+ * PIPed activity will be resized accordingly and overlay will show available buttons.
+ */
+ public void onRecentsResumed() {
+ if (!mPipManager.isPipShown()) {
+ return;
+ }
+ mIsRecentsShown = true;
+ mIsPipFocusedInRecent = true;
+ mPipManager.resizePinnedStack(STATE_PIP_RECENTS_FOCUSED);
+ // Overlay view will be added after the resize animation ends, if any.
+ }
+
+ /**
+ * Called when Recents is paused.
+ * PIPed activity will be resized accordingly and overlay will hide available buttons.
+ */
+ public void onRecentsPaused() {
+ mIsRecentsShown = false;
+ mIsPipFocusedInRecent = false;
+ removePipRecentsOverlayView();
+
+ if (mPipManager.isPipShown()) {
+ mPipManager.resizePinnedStack(STATE_PIP_OVERLAY);
+ }
+ }
+
+ /**
+ * Returns {@code true} if recents is shown.
+ */
+ boolean isRecentsShown() {
+ return mIsRecentsShown;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
index f432808..c6e4356 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
@@ -35,11 +35,11 @@
private static final Typeface MEDIUM = Typeface.create("sans-serif-medium", Typeface.NORMAL);
private final Context mContext;
- private final LayoutInflater mInflater;
+ protected final LayoutInflater mInflater;
private final SpTexts mSpTexts;
private Callback mCallback;
- private Object mSelectedValue;
+ protected Object mSelectedValue;
public SegmentedButtons(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -65,13 +65,21 @@
final Object tag = c.getTag();
final boolean selected = Objects.equals(mSelectedValue, tag);
c.setSelected(selected);
- c.setTypeface(selected ? MEDIUM : REGULAR);
+ setSelectedStyle(c, selected);
}
fireOnSelected(fromClick);
}
+ protected void setSelectedStyle(TextView textView, boolean selected) {
+ textView.setTypeface(selected ? MEDIUM : REGULAR);
+ }
+
+ public Button inflateButton() {
+ return (Button) mInflater.inflate(R.layout.segmented_button, this, false);
+ }
+
public void addButton(int labelResId, int contentDescriptionResId, Object value) {
- final Button b = (Button) mInflater.inflate(R.layout.segmented_button, this, false);
+ final Button b = inflateButton();
b.setTag(LABEL_RES_KEY, labelResId);
b.setText(labelResId);
b.setContentDescription(getResources().getString(contentDescriptionResId));
diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml
index 32e1e6d..08257b6 100644
--- a/packages/VpnDialogs/AndroidManifest.xml
+++ b/packages/VpnDialogs/AndroidManifest.xml
@@ -24,7 +24,7 @@
<application android:label="VpnDialogs"
android:allowBackup="false" >
<activity android:name=".ConfirmDialog"
- android:theme="@*android:style/Theme.Material.DayNight.Dialog.Alert">
+ android:theme="@android:style/Theme.Material.Light.Dialog.Alert">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.DEFAULT"/>
@@ -32,7 +32,7 @@
</activity>
<activity android:name=".ManageDialog"
- android:theme="@*android:style/Theme.Material.DayNight.Dialog.Alert"
+ android:theme="@android:style/Theme.Material.Light.Dialog.Alert"
android:noHistory="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
diff --git a/packages/WallpaperCropper/res/values/styles.xml b/packages/WallpaperCropper/res/values/styles.xml
index 0f9e247..6a56afd 100644
--- a/packages/WallpaperCropper/res/values/styles.xml
+++ b/packages/WallpaperCropper/res/values/styles.xml
@@ -15,7 +15,7 @@
-->
<resources>
- <style name="Theme.WallpaperCropper" parent="@*android:style/Theme.Material.DayNight">
+ <style name="Theme.WallpaperCropper" parent="@android:style/Theme.Material.Light">
<item name="android:actionBarStyle">@style/WallpaperCropperActionBar</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowActionBarOverlay">true</item>
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index 81f63ae..9ec6e8d 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -380,6 +380,7 @@
Log.e(RenderScript.LOG_TAG, "Couldn't invoke registerNativeAllocation:" + e);
throw new RSRuntimeException("Couldn't invoke registerNativeAllocation:" + e);
}
+ guard.open("destroy");
}
Allocation(long id, RenderScript rs, Type t, int usage, MipmapControl mips) {
@@ -1915,6 +1916,7 @@
if (type.getID(rs) == 0) {
throw new RSInvalidStateException("Bad Type");
}
+ // TODO: What if there is an exception after this? The native allocation would leak.
long id = rs.nAllocationCreateTyped(type.getID(rs), mips.mID, usage, 0);
if (id == 0) {
throw new RSRuntimeException("Allocation creation failed.");
diff --git a/rs/java/android/renderscript/BaseObj.java b/rs/java/android/renderscript/BaseObj.java
index 1372ab7..f95af16 100644
--- a/rs/java/android/renderscript/BaseObj.java
+++ b/rs/java/android/renderscript/BaseObj.java
@@ -16,6 +16,7 @@
package android.renderscript;
+import dalvik.system.CloseGuard;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
@@ -69,6 +70,7 @@
}
private long mID;
+ final CloseGuard guard = CloseGuard.get();
private boolean mDestroyed;
private String mName;
RenderScript mRS;
@@ -119,6 +121,7 @@
}
if (shouldDestroy) {
+ guard.close();
// must include nObjDestroy in the critical section
ReentrantReadWriteLock.ReadLock rlock = mRS.mRWLock.readLock();
rlock.lock();
@@ -133,8 +136,14 @@
}
protected void finalize() throws Throwable {
- helpDestroy();
- super.finalize();
+ try {
+ if (guard != null) {
+ guard.warnIfOpen();
+ }
+ helpDestroy();
+ } finally {
+ super.finalize();
+ }
}
/**
diff --git a/rs/java/android/renderscript/Element.java b/rs/java/android/renderscript/Element.java
index 6efb6d6..50226ac 100644
--- a/rs/java/android/renderscript/Element.java
+++ b/rs/java/android/renderscript/Element.java
@@ -808,6 +808,7 @@
mSize += mElements[ct].mSize * mArraySizes[ct];
}
updateVisibleSubElements();
+ guard.open("destroy");
}
Element(long id, RenderScript rs, DataType dt, DataKind dk, boolean norm, int size) {
@@ -827,6 +828,7 @@
mKind = dk;
mNormalized = norm;
mVectorSize = size;
+ guard.open("destroy");
}
Element(long id, RenderScript rs) {
diff --git a/rs/java/android/renderscript/FileA3D.java b/rs/java/android/renderscript/FileA3D.java
index 9d8f162..278d309 100644
--- a/rs/java/android/renderscript/FileA3D.java
+++ b/rs/java/android/renderscript/FileA3D.java
@@ -170,6 +170,7 @@
FileA3D(long id, RenderScript rs, InputStream stream) {
super(id, rs);
mInputStream = stream;
+ guard.open("destroy");
}
private void initEntries() {
diff --git a/rs/java/android/renderscript/Font.java b/rs/java/android/renderscript/Font.java
index 4318b9d..d5ca31e 100644
--- a/rs/java/android/renderscript/Font.java
+++ b/rs/java/android/renderscript/Font.java
@@ -150,6 +150,7 @@
Font(long id, RenderScript rs) {
super(id, rs);
+ guard.open("destroy");
}
/**
diff --git a/rs/java/android/renderscript/Mesh.java b/rs/java/android/renderscript/Mesh.java
index 13c8e1c..9e4f905 100644
--- a/rs/java/android/renderscript/Mesh.java
+++ b/rs/java/android/renderscript/Mesh.java
@@ -91,6 +91,7 @@
Mesh(long id, RenderScript rs) {
super(id, rs);
+ guard.open("destroy");
}
/**
diff --git a/rs/java/android/renderscript/Program.java b/rs/java/android/renderscript/Program.java
index 3eb9b75..772021c 100644
--- a/rs/java/android/renderscript/Program.java
+++ b/rs/java/android/renderscript/Program.java
@@ -76,6 +76,7 @@
Program(long id, RenderScript rs) {
super(id, rs);
+ guard.open("destroy");
}
/**
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 9beaba3..2650e5a 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -1031,7 +1031,6 @@
- long mDev;
long mContext;
private boolean mDestroyed = false;
@@ -1426,8 +1425,8 @@
RenderScript rs = new RenderScript(ctx);
- rs.mDev = rs.nDeviceCreate();
- rs.mContext = rs.nContextCreate(rs.mDev, flags, sdkVersion, ct.mID);
+ long device = rs.nDeviceCreate();
+ rs.mContext = rs.nContextCreate(device, flags, sdkVersion, ct.mID);
rs.mContextType = ct;
rs.mContextFlags = flags;
rs.mContextSdkVersion = sdkVersion;
@@ -1635,9 +1634,6 @@
}
nContextDestroy();
-
- nDeviceDestroy(mDev);
- mDev = 0;
}
}
diff --git a/rs/java/android/renderscript/RenderScriptGL.java b/rs/java/android/renderscript/RenderScriptGL.java
index 6178994..be1f899 100644
--- a/rs/java/android/renderscript/RenderScriptGL.java
+++ b/rs/java/android/renderscript/RenderScriptGL.java
@@ -177,9 +177,9 @@
mWidth = 0;
mHeight = 0;
- mDev = nDeviceCreate();
+ long device = nDeviceCreate();
int dpi = ctx.getResources().getDisplayMetrics().densityDpi;
- mContext = nContextCreateGL(mDev, 0, sdkVersion,
+ mContext = nContextCreateGL(device, 0, sdkVersion,
mSurfaceConfig.mColorMin, mSurfaceConfig.mColorPref,
mSurfaceConfig.mAlphaMin, mSurfaceConfig.mAlphaPref,
mSurfaceConfig.mDepthMin, mSurfaceConfig.mDepthPref,
diff --git a/rs/java/android/renderscript/Sampler.java b/rs/java/android/renderscript/Sampler.java
index a4edbb5..5c4bae9 100644
--- a/rs/java/android/renderscript/Sampler.java
+++ b/rs/java/android/renderscript/Sampler.java
@@ -51,6 +51,7 @@
Sampler(long id, RenderScript rs) {
super(id, rs);
+ guard.open("destroy");
}
/**
diff --git a/rs/java/android/renderscript/Script.java b/rs/java/android/renderscript/Script.java
index f6f93cb..fc3280b 100644
--- a/rs/java/android/renderscript/Script.java
+++ b/rs/java/android/renderscript/Script.java
@@ -41,6 +41,7 @@
mScript = s;
mSlot = slot;
mSig = sig;
+ guard.open("destroy");
}
}
@@ -118,6 +119,7 @@
super(id, rs);
mScript = s;
mSlot = slot;
+ guard.open("destroy");
}
}
@@ -357,6 +359,19 @@
super(id, rs);
mInIdsBuffer = new long[1];
+
+ /* The constructors for the derived classes (including ScriptIntrinsic
+ * derived classes and ScriptC derived classes generated by Slang
+ * reflection) seem to be simple enough, so we just put the guard.open()
+ * call here, rather than in the end of the constructor for the derived
+ * class. This, of course, assumes the derived constructor would not
+ * throw any exception after calling this constructor.
+ *
+ * If new derived classes are added with more complicated constructors
+ * that throw exceptions, this call has to be (duplicated and) moved
+ * to the end of each derived class constructor.
+ */
+ guard.open("destroy");
}
/**
diff --git a/rs/java/android/renderscript/ScriptGroup.java b/rs/java/android/renderscript/ScriptGroup.java
index 9357c3bb..219f16b 100644
--- a/rs/java/android/renderscript/ScriptGroup.java
+++ b/rs/java/android/renderscript/ScriptGroup.java
@@ -148,6 +148,8 @@
fieldIDs, values, sizes, depClosures, depFieldIDs);
setID(id);
+
+ guard.open("destroy");
}
Closure(RenderScript rs, Script.InvokeID invokeID,
@@ -181,6 +183,8 @@
values, sizes);
setID(id);
+
+ guard.open("destroy");
}
private void retrieveValueAndDependenceInfo(RenderScript rs,
@@ -382,6 +386,7 @@
ScriptGroup(long id, RenderScript rs) {
super(id, rs);
+ guard.open("destroy");
}
ScriptGroup(RenderScript rs, String name, List<Closure> closures,
@@ -398,6 +403,7 @@
}
long id = rs.nScriptGroup2Create(name, RenderScript.getCachePath(), closureIDs);
setID(id);
+ guard.open("destroy");
}
/**
diff --git a/rs/java/android/renderscript/Type.java b/rs/java/android/renderscript/Type.java
index dc23785..9252898 100644
--- a/rs/java/android/renderscript/Type.java
+++ b/rs/java/android/renderscript/Type.java
@@ -227,6 +227,7 @@
Type(long id, RenderScript rs) {
super(id, rs);
+ guard.open("destroy");
}
@Override
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 4b96e7a..e256ecd 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1262,7 +1262,7 @@
Service service = componentNameToServiceMap.get(componentName);
// Ignore non-encryption-aware services until user is unlocked
- if (!isUnlocked && !installedService.isEncryptionAware()) {
+ if (!isUnlocked && !installedService.isDirectBootAware()) {
Slog.d(LOG_TAG, "Ignoring non-encryption-aware service " + componentName);
continue;
}
@@ -1784,10 +1784,15 @@
userState.mEnabledServices.contains(userState.mServiceChangingSoftKeyboardMode);
if (!serviceChangingSoftKeyboardModeIsEnabled) {
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
- 0,
- userState.mUserId);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
+ 0,
+ userState.mUserId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
userState.mSoftKeyboardShowMode = 0;
userState.mServiceChangingSoftKeyboardMode = null;
}
@@ -3491,6 +3496,8 @@
reportedWindow.setLayer(window.layer);
reportedWindow.setFocused(window.focused);
reportedWindow.setBoundsInScreen(window.boundsInScreen);
+ reportedWindow.setTitle(window.title);
+ reportedWindow.setAnchorId(window.accessibilityIdOfAnchor);
final int parentId = findWindowIdLocked(window.parentToken);
if (parentId >= 0) {
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 89b145e2..1b0d3ac 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -164,7 +164,8 @@
onUserStopped(userId);
} else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
reloadWidgetsMaskedStateForGroup(userId);
- } else if (Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED.equals(action)) {
+ } else if (Intent.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action)
+ || Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) {
synchronized (mLock) {
reloadWidgetsMaskedState(userId);
}
@@ -288,7 +289,8 @@
userFilter, null, null);
IntentFilter offModeFilter = new IntentFilter();
- offModeFilter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
+ offModeFilter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
+ offModeFilter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
offModeFilter, null, null);
@@ -742,8 +744,8 @@
}
@Override
- public int[] startListening(IAppWidgetHost callbacks, String callingPackage,
- int hostId, List<RemoteViews> updatedViews) {
+ public ParceledListSlice<RemoteViews> startListening(IAppWidgetHost callbacks,
+ String callingPackage, int hostId, int[] appWidgetIds, int[] updatedIds) {
final int userId = UserHandle.getCallingUserId();
if (DEBUG) {
@@ -760,21 +762,21 @@
// sure the caller can only access hosts it owns.
HostId id = new HostId(Binder.getCallingUid(), hostId, callingPackage);
Host host = lookupOrAddHostLocked(id);
-
host.callbacks = callbacks;
- updatedViews.clear();
-
- ArrayList<Widget> instances = host.widgets;
- int N = instances.size();
- int[] updatedIds = new int[N];
+ int N = appWidgetIds.length;
+ ArrayList<RemoteViews> outViews = new ArrayList<>(N);
+ RemoteViews rv;
+ int added = 0;
for (int i = 0; i < N; i++) {
- Widget widget = instances.get(i);
- updatedIds[i] = widget.appWidgetId;
- updatedViews.add(cloneIfLocalBinder(widget.getEffectiveViewsLocked()));
+ rv = host.getPendingViewsForId(appWidgetIds[i]);
+ if (rv != null) {
+ updatedIds[added] = appWidgetIds[i];
+ outViews.add(rv);
+ added++;
+ }
}
-
- return updatedIds;
+ return new ParceledListSlice<>(outViews);
}
}
@@ -1882,6 +1884,10 @@
}
private void scheduleNotifyUpdateAppWidgetLocked(Widget widget, RemoteViews updateViews) {
+ long requestTime = SystemClock.uptimeMillis();
+ if (widget != null) {
+ widget.lastUpdateTime = requestTime;
+ }
if (widget == null || widget.provider == null || widget.provider.zombie
|| widget.host.callbacks == null || widget.host.zombie) {
return;
@@ -1891,6 +1897,7 @@
args.arg1 = widget.host;
args.arg2 = widget.host.callbacks;
args.arg3 = updateViews;
+ args.arg4 = requestTime;
args.argi1 = widget.appWidgetId;
mCallbackHandler.obtainMessage(
@@ -1899,9 +1906,10 @@
}
private void handleNotifyUpdateAppWidget(Host host, IAppWidgetHost callbacks,
- int appWidgetId, RemoteViews views) {
+ int appWidgetId, RemoteViews views, long requestTime) {
try {
callbacks.updateAppWidget(appWidgetId, views);
+ host.lastWidgetUpdateTime = requestTime;
} catch (RemoteException re) {
synchronized (mLock) {
Slog.e(TAG, "Widget host dead: " + host.id, re);
@@ -3398,10 +3406,11 @@
Host host = (Host) args.arg1;
IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
RemoteViews views = (RemoteViews) args.arg3;
+ long requestTime = (Long) args.arg4;
final int appWidgetId = args.argi1;
args.recycle();
- handleNotifyUpdateAppWidget(host, callbacks, appWidgetId, views);
+ handleNotifyUpdateAppWidget(host, callbacks, appWidgetId, views, requestTime);
} break;
case MSG_NOTIFY_PROVIDER_CHANGED: {
@@ -3769,6 +3778,7 @@
boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
int tag = TAG_UNDEFINED; // for use while saving state (the index)
+ long lastWidgetUpdateTime; // last time we were successfully able to send an update.
public int getUserId() {
return UserHandle.getUserId(id.uid);
@@ -3790,6 +3800,23 @@
return false;
}
+ /**
+ * Returns the RemoveViews for the provided widget id if an update is pending
+ * for that widget.
+ */
+ public RemoteViews getPendingViewsForId(int appWidgetId) {
+ long updateTime = lastWidgetUpdateTime;
+ int N = widgets.size();
+ for (int i = 0; i < N; i++) {
+ Widget widget = widgets.get(i);
+ if (widget.appWidgetId == appWidgetId
+ && widget.lastUpdateTime > updateTime) {
+ return cloneIfLocalBinder(widget.getEffectiveViewsLocked());
+ }
+ }
+ return null;
+ }
+
@Override
public String toString() {
return "Host{" + id + (zombie ? " Z" : "") + '}';
@@ -3860,6 +3887,7 @@
RemoteViews maskedViews;
Bundle options;
Host host;
+ long lastUpdateTime;
@Override
public String toString() {
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index fd57af6..c38a89e 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -446,8 +446,12 @@
int[] ops) {
mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
Binder.getCallingPid(), Binder.getCallingUid(), null);
+ String resolvedPackageName = resolvePackageName(uid, packageName);
+ if (resolvedPackageName == null) {
+ return Collections.emptyList();
+ }
synchronized (this) {
- Ops pkgOps = getOpsLocked(uid, packageName, false);
+ Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false);
if (pkgOps == null) {
return null;
}
@@ -465,7 +469,7 @@
private void pruneOp(Op op, int uid, String packageName) {
if (op.time == 0 && op.rejectTime == 0) {
- Ops ops = getOpsLocked(uid, packageName, false);
+ Ops ops = getOpsRawLocked(uid, packageName, false);
if (ops != null) {
ops.remove(op.op);
if (ops.size() <= 0) {
@@ -879,8 +883,12 @@
public int checkOperation(int code, int uid, String packageName) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
+ String resolvedPackageName = resolvePackageName(uid, packageName);
+ if (resolvedPackageName == null) {
+ return AppOpsManager.MODE_IGNORED;
+ }
synchronized (this) {
- if (isOpRestricted(uid, code, packageName)) {
+ if (isOpRestricted(uid, code, resolvedPackageName)) {
return AppOpsManager.MODE_IGNORED;
}
code = AppOpsManager.opToSwitch(code);
@@ -891,7 +899,7 @@
return uidMode;
}
}
- Op op = getOpLocked(code, uid, packageName, false);
+ Op op = getOpLocked(code, uid, resolvedPackageName, false);
if (op == null) {
return AppOpsManager.opToDefaultMode(code);
}
@@ -975,6 +983,7 @@
@Override
public int checkPackage(int uid, String packageName) {
+ Preconditions.checkNotNull(packageName);
synchronized (this) {
if (getOpsRawLocked(uid, packageName, true) != null) {
return AppOpsManager.MODE_ALLOWED;
@@ -988,26 +997,39 @@
public int noteProxyOperation(int code, String proxyPackageName,
int proxiedUid, String proxiedPackageName) {
verifyIncomingOp(code);
- final int proxyMode = noteOperationUnchecked(code, Binder.getCallingUid(),
- proxyPackageName, -1, null);
+ final int proxyUid = Binder.getCallingUid();
+ String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
+ if (resolveProxyPackageName == null) {
+ return AppOpsManager.MODE_IGNORED;
+ }
+ final int proxyMode = noteOperationUnchecked(code, proxyUid,
+ resolveProxyPackageName, -1, null);
if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
return proxyMode;
}
- return noteOperationUnchecked(code, proxiedUid, proxiedPackageName,
- Binder.getCallingUid(), proxyPackageName);
+ String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
+ if (resolveProxiedPackageName == null) {
+ return AppOpsManager.MODE_IGNORED;
+ }
+ return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
+ proxyMode, resolveProxyPackageName);
}
@Override
public int noteOperation(int code, int uid, String packageName) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
- return noteOperationUnchecked(code, uid, packageName, 0, null);
+ String resolvedPackageName = resolvePackageName(uid, packageName);
+ if (resolvedPackageName == null) {
+ return AppOpsManager.MODE_IGNORED;
+ }
+ return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
}
private int noteOperationUnchecked(int code, int uid, String packageName,
int proxyUid, String proxyPackageName) {
synchronized (this) {
- Ops ops = getOpsLocked(uid, packageName, true);
+ Ops ops = getOpsRawLocked(uid, packageName, true);
if (ops == null) {
if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
+ " package " + packageName);
@@ -1055,16 +1077,20 @@
public int startOperation(IBinder token, int code, int uid, String packageName) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
+ String resolvedPackageName = resolvePackageName(uid, packageName);
+ if (resolvedPackageName == null) {
+ return AppOpsManager.MODE_IGNORED;
+ }
ClientState client = (ClientState)token;
synchronized (this) {
- Ops ops = getOpsLocked(uid, packageName, true);
+ Ops ops = getOpsRawLocked(uid, resolvedPackageName, true);
if (ops == null) {
if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid
- + " package " + packageName);
+ + " package " + resolvedPackageName);
return AppOpsManager.MODE_ERRORED;
}
Op op = getOpLocked(ops, code, true);
- if (isOpRestricted(uid, code, packageName)) {
+ if (isOpRestricted(uid, code, resolvedPackageName)) {
return AppOpsManager.MODE_IGNORED;
}
final int switchCode = AppOpsManager.opToSwitch(code);
@@ -1074,7 +1100,7 @@
if (uidMode != AppOpsManager.MODE_ALLOWED) {
if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
+ switchCode + " (" + code + ") uid " + uid + " package "
- + packageName);
+ + resolvedPackageName);
op.rejectTime = System.currentTimeMillis();
return uidMode;
}
@@ -1082,12 +1108,13 @@
final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
if (DEBUG) Log.d(TAG, "startOperation: reject #" + op.mode + " for code "
- + switchCode + " (" + code + ") uid " + uid + " package " + packageName);
+ + switchCode + " (" + code + ") uid " + uid + " package "
+ + resolvedPackageName);
op.rejectTime = System.currentTimeMillis();
return switchOp.mode;
}
if (DEBUG) Log.d(TAG, "startOperation: allowing code " + code + " uid " + uid
- + " package " + packageName);
+ + " package " + resolvedPackageName);
if (op.nesting == 0) {
op.time = System.currentTimeMillis();
op.rejectTime = 0;
@@ -1105,9 +1132,16 @@
public void finishOperation(IBinder token, int code, int uid, String packageName) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
- ClientState client = (ClientState)token;
+ String resolvedPackageName = resolvePackageName(uid, packageName);
+ if (resolvedPackageName == null) {
+ return;
+ }
+ if (!(token instanceof ClientState)) {
+ return;
+ }
+ ClientState client = (ClientState) token;
synchronized (this) {
- Op op = getOpLocked(code, uid, packageName, true);
+ Op op = getOpLocked(code, uid, resolvedPackageName, true);
if (op == null) {
return;
}
@@ -1123,6 +1157,9 @@
@Override
public int permissionToOpCode(String permission) {
+ if (permission == null) {
+ return AppOpsManager.OP_NONE;
+ }
return AppOpsManager.permissionToOpCode(permission);
}
@@ -1172,15 +1209,6 @@
return uidState;
}
- private Ops getOpsLocked(int uid, String packageName, boolean edit) {
- if (uid == 0) {
- packageName = "root";
- } else if (uid == Process.SHELL_UID) {
- packageName = "com.android.shell";
- }
- return getOpsRawLocked(uid, packageName, edit);
- }
-
private Ops getOpsRawLocked(int uid, String packageName, boolean edit) {
UidState uidState = getUidStateLocked(uid, edit);
if (uidState == null) {
@@ -1266,7 +1294,7 @@
}
private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
- Ops ops = getOpsLocked(uid, packageName, edit);
+ Ops ops = getOpsRawLocked(uid, packageName, edit);
if (ops == null) {
return null;
}
@@ -1324,7 +1352,7 @@
if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
// If we are the system, bypass user restrictions for certain codes
synchronized (this) {
- Ops ops = getOpsLocked(uid, packageName, true);
+ Ops ops = getOpsRawLocked(uid, packageName, true);
if ((ops != null) && ops.isPrivileged) {
return false;
}
@@ -1589,7 +1617,7 @@
out.startTag(null, "uid");
out.attribute(null, "n", Integer.toString(pkg.getUid()));
synchronized (this) {
- Ops ops = getOpsLocked(pkg.getUid(), pkg.getPackageName(), false);
+ Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), false);
// Should always be present as the list of PackageOps is generated
// from Ops.
if (ops != null) {
@@ -2181,6 +2209,7 @@
@Override
public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
checkSystemUid("setUserRestrictions");
+ Preconditions.checkNotNull(restrictions);
Preconditions.checkNotNull(token);
final boolean[] opRestrictions = getOrCreateUserRestrictionsForToken(token, userHandle);
for (int i = 0; i < opRestrictions.length; ++i) {
@@ -2395,6 +2424,17 @@
}
}
+ private static String resolvePackageName(int uid, String packageName) {
+ if (uid == 0) {
+ return "root";
+ } else if (uid == Process.SHELL_UID) {
+ return "com.android.shell";
+ } else if (uid == Process.SYSTEM_UID && packageName == null) {
+ return "android";
+ }
+ return packageName;
+ }
+
private static String[] getPackagesForUid(int uid) {
String[] packageNames = null;
try {
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 799a763..0a814ab 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -92,6 +92,7 @@
private static final int MESSAGE_BLUETOOTH_STATE_CHANGE = 60;
private static final int MESSAGE_TIMEOUT_BIND = 100;
private static final int MESSAGE_TIMEOUT_UNBIND = 101;
+ private static final int MESSAGE_GET_NAME_AND_ADDRESS = 200;
private static final int MESSAGE_USER_SWITCHED = 300;
private static final int MESSAGE_USER_UNLOCKED = 301;
private static final int MESSAGE_ADD_PROXY_DELAYED = 400;
@@ -599,8 +600,8 @@
sendEnableMsg(true);
}
return true;
-
}
+
public boolean enable() {
if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
(!checkIfCallerIsForegroundUser())) {
@@ -763,9 +764,8 @@
sendEnableMsg(mQuietEnableExternal);
} else if (!isNameAndAddressSet()) {
if (DBG) Slog.d(TAG, "Getting adapter name and address");
- enable();
- waitForOnOff(true, false);
- disable(true);
+ Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
+ mHandler.sendMessage(getMsg);
}
}
@@ -1076,6 +1076,8 @@
private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
private class BluetoothHandler extends Handler {
+ boolean mGetNameAddressOnly = false;
+
public BluetoothHandler(Looper looper) {
super(looper);
}
@@ -1084,6 +1086,37 @@
public void handleMessage(Message msg) {
if (DBG) Slog.d (TAG, "Message: " + msg.what);
switch (msg.what) {
+ case MESSAGE_GET_NAME_AND_ADDRESS:
+ if (DBG) Slog.d(TAG, "MESSAGE_GET_NAME_AND_ADDRESS");
+ synchronized(mConnection) {
+ if ((mBluetooth == null) && (!mBinding)) {
+ if (DBG) Slog.d(TAG, "Binding to service to get name and address");
+ mGetNameAddressOnly = true;
+ Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
+ mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS);
+ Intent i = new Intent(IBluetooth.class.getName());
+ if (!doBind(i, mConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
+ UserHandle.CURRENT)) {
+ mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
+ } else {
+ mBinding = true;
+ }
+ } else if (mBluetooth != null) {
+ try {
+ storeNameAndAddress(mBluetooth.getName(),
+ mBluetooth.getAddress());
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Unable to grab names", re);
+ }
+ if (mGetNameAddressOnly && !mEnable) {
+ unbindAndFinish();
+ }
+ mGetNameAddressOnly = false;
+ }
+ }
+ break;
+
case MESSAGE_ENABLE:
if (DBG) {
Slog.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
@@ -1177,6 +1210,12 @@
mBluetoothBinder = service;
mBluetooth = IBluetooth.Stub.asInterface(service);
+ if (!isNameAndAddressSet()) {
+ Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
+ mHandler.sendMessage(getMsg);
+ if (mGetNameAddressOnly) return;
+ }
+
try {
boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,
Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);
@@ -1187,15 +1226,6 @@
Slog.e(TAG,"Unable to call configHciSnoopLog", e);
}
- if (!isNameAndAddressSet()) {
- try {
- storeNameAndAddress(mBluetooth.getName(),
- mBluetooth.getAddress());
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to grab names", re);
- }
- }
-
//Register callback object
try {
mBluetooth.registerCallback(mBluetoothCallback);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 95d3cc3..a4d6be5 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -371,8 +371,6 @@
private int mNetTransitionWakeLockTimeout;
private final PowerManager.WakeLock mPendingIntentWakeLock;
- private InetAddress mDefaultDns;
-
// used in DBG mode to track inet condition reports
private static final int INET_CONDITION_LOG_MAX_SIZE = 15;
private ArrayList mInetLog;
@@ -645,19 +643,6 @@
}
}
- // read our default dns server ip
- String dns = Settings.Global.getString(context.getContentResolver(),
- Settings.Global.DEFAULT_DNS_SERVER);
- if (dns == null || dns.length() == 0) {
- dns = context.getResources().getString(
- com.android.internal.R.string.config_default_dns_server);
- }
- try {
- mDefaultDns = NetworkUtils.numericToInetAddress(dns);
- } catch (IllegalArgumentException e) {
- loge("Error setting defaultDns using " + dns);
- }
-
mReleasePendingIntentDelayMs = Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, 5_000);
@@ -4149,14 +4134,8 @@
// }
updateTcpBufferSizes(networkAgent);
- // TODO: deprecate and remove mDefaultDns when we can do so safely. See http://b/18327075
- // In L, we used it only when the network had Internet access but provided no DNS servers.
- // For now, just disable it, and if disabling it doesn't break things, remove it.
- // final boolean useDefaultDns = networkAgent.networkCapabilities.hasCapability(
- // NET_CAPABILITY_INTERNET);
- final boolean useDefaultDns = false;
final boolean flushDns = updateRoutes(newLp, oldLp, netId);
- updateDnses(newLp, oldLp, netId, flushDns, useDefaultDns);
+ updateDnses(newLp, oldLp, netId, flushDns);
updateClat(newLp, oldLp, networkAgent);
if (isDefaultNetwork(networkAgent)) {
@@ -4260,16 +4239,9 @@
}
private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId,
- boolean flush, boolean useDefaultDns) {
+ boolean flush) {
if (oldLp == null || (newLp.isIdenticalDnses(oldLp) == false)) {
Collection<InetAddress> dnses = newLp.getDnsServers();
- if (dnses.size() == 0 && mDefaultDns != null && useDefaultDns) {
- dnses = new ArrayList();
- dnses.add(mDefaultDns);
- if (DBG) {
- loge("no dns provided for netId " + netId + ", so using defaults");
- }
- }
if (DBG) log("Setting Dns servers for network " + netId + " to " + dnses);
try {
mNetd.setDnsServersForNetwork(netId, NetworkUtils.makeStrings(dnses),
diff --git a/services/core/java/com/android/server/GraphicsStatsService.java b/services/core/java/com/android/server/GraphicsStatsService.java
index e29515f..ecbe1ca 100644
--- a/services/core/java/com/android/server/GraphicsStatsService.java
+++ b/services/core/java/com/android/server/GraphicsStatsService.java
@@ -51,7 +51,7 @@
* 2) ASHMEM_SIZE (for scratch space used during dumping)
* 3) ASHMEM_SIZE * HISTORY_SIZE
*
- * This is currently under 16KiB total memory in the worst case of
+ * This is currently under 20KiB total memory in the worst case of
* 20 processes in history + 10 unique active processes.
*
* @hide */
@@ -59,7 +59,7 @@
public static final String GRAPHICS_STATS_SERVICE = "graphicsstats";
private static final String TAG = "GraphicsStatsService";
- private static final int ASHMEM_SIZE = 296;
+ private static final int ASHMEM_SIZE = 464;
private static final int HISTORY_SIZE = 20;
private final Context mContext;
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index b8cbf16..811e34e 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -125,6 +125,7 @@
import android.widget.RadioButton;
import android.widget.Switch;
import android.widget.TextView;
+import android.widget.Toast;
import java.io.File;
import java.io.FileDescriptor;
@@ -452,6 +453,7 @@
private AlertDialog.Builder mDialogBuilder;
private AlertDialog mSwitchingDialog;
private View mSwitchingDialogTitleView;
+ private Toast mSubtypeSwitchedByShortCutToast;
private InputMethodInfo[] mIms;
private int[] mSubtypeIds;
private LocaleList mLastSystemLocales;
@@ -2952,6 +2954,27 @@
return;
}
setInputMethodLocked(nextSubtype.mImi.getId(), nextSubtype.mSubtypeId);
+ if (mSubtypeSwitchedByShortCutToast != null) {
+ mSubtypeSwitchedByShortCutToast.cancel();
+ mSubtypeSwitchedByShortCutToast = null;
+ }
+ if ((mImeWindowVis & InputMethodService.IME_VISIBLE) != 0) {
+ // IME window is shown. The user should be able to visually understand that the
+ // subtype is changed in most of cases. To avoid UI overlap, we do not show a toast
+ // in this case.
+ return;
+ }
+ final InputMethodInfo newInputMethodInfo = mMethodMap.get(mCurMethodId);
+ if (newInputMethodInfo == null) {
+ return;
+ }
+ final CharSequence toastText = InputMethodUtils.getImeAndSubtypeDisplayName(mContext,
+ newInputMethodInfo, mCurrentSubtype);
+ if (!TextUtils.isEmpty(toastText)) {
+ mSubtypeSwitchedByShortCutToast = Toast.makeText(mContext, toastText.toString(),
+ Toast.LENGTH_SHORT);
+ mSubtypeSwitchedByShortCutToast.show();
+ }
}
}
@@ -3823,6 +3846,22 @@
}
}
+ private static String imeWindowStatusToString(final int imeWindowVis) {
+ final StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ if ((imeWindowVis & InputMethodService.IME_ACTIVE) != 0) {
+ sb.append("Active");
+ first = false;
+ }
+ if ((imeWindowVis & InputMethodService.IME_VISIBLE) != 0) {
+ if (!first) {
+ sb.append("|");
+ }
+ sb.append("Visible");
+ }
+ return sb.toString();
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -3870,6 +3909,7 @@
method = mCurMethod;
p.println(" mCurMethod=" + mCurMethod);
p.println(" mEnabledSession=" + mEnabledSession);
+ p.println(" mImeWindowVis=" + imeWindowStatusToString(mImeWindowVis));
p.println(" mShowRequested=" + mShowRequested
+ " mShowExplicitlyRequested=" + mShowExplicitlyRequested
+ " mShowForced=" + mShowForced
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 994e1d0..440d8b7 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -1247,6 +1247,11 @@
}
private void onVolumeCreatedLocked(VolumeInfo vol) {
+ if (mPms.isOnlyCoreApps()) {
+ Slog.d(TAG, "System booted in core-only mode; ignoring volume " + vol.getId());
+ return;
+ }
+
if (vol.type == VolumeInfo.TYPE_EMULATED) {
final StorageManager storage = mContext.getSystemService(StorageManager.class);
final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 1632f92..8a0a62a 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -65,6 +65,7 @@
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
+import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -75,11 +76,13 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.StorageManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
@@ -91,6 +94,7 @@
import java.io.File;
import java.io.FileDescriptor;
+import java.io.IOException;
import java.io.PrintWriter;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
@@ -107,7 +111,6 @@
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
@@ -126,7 +129,9 @@
private static final String TAG = "AccountManagerService";
private static final String DATABASE_NAME = "accounts.db";
- private static final int DATABASE_VERSION = 9;
+ private static final int PRE_N_DATABASE_VERSION = 9;
+ private static final int CE_DATABASE_VERSION = 10;
+ private static final int DE_DATABASE_VERSION = 1;
private static final int MAX_DEBUG_DB_SIZE = 64;
@@ -176,6 +181,15 @@
private static final String META_VALUE = "value";
private static final String TABLE_SHARED_ACCOUNTS = "shared_accounts";
+ private static final String SHARED_ACCOUNTS_ID = "_id";
+
+ private static final String PRE_N_DATABASE_NAME = "accounts.db";
+ private static final String CE_DATABASE_NAME = "accounts_ce.db";
+ private static final String DE_DATABASE_NAME = "accounts_de.db";
+ private static final String CE_DB_PREFIX = "ceDb.";
+ private static final String CE_TABLE_ACCOUNTS = CE_DB_PREFIX + TABLE_ACCOUNTS;
+ private static final String CE_TABLE_AUTHTOKENS = CE_DB_PREFIX + TABLE_AUTHTOKENS;
+ private static final String CE_TABLE_EXTRAS = CE_DB_PREFIX + TABLE_EXTRAS;
private static final String[] ACCOUNT_TYPE_COUNT_PROJECTION =
new String[] { ACCOUNTS_TYPE, ACCOUNTS_TYPE_COUNT};
@@ -214,7 +228,7 @@
static class UserAccounts {
private final int userId;
- private final DatabaseHelper openHelper;
+ private final DeDatabaseHelper openHelper;
private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
credentialsPermissionNotificationIds =
new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
@@ -255,15 +269,15 @@
UserAccounts(Context context, int userId) {
this.userId = userId;
synchronized (cacheLock) {
- openHelper = new DatabaseHelper(context, userId);
+ openHelper = DeDatabaseHelper.create(context, userId);
}
}
}
- private final SparseArray<UserAccounts> mUsers = new SparseArray<UserAccounts>();
+ private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
+ private final SparseBooleanArray mUnlockedUsers = new SparseBooleanArray();
- private static AtomicReference<AccountManagerService> sThis =
- new AtomicReference<AccountManagerService>();
+ private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
/**
@@ -381,6 +395,11 @@
*/
private void validateAccountsInternal(
UserAccounts accounts, boolean invalidateAuthenticatorCache) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "validateAccountsInternal " + accounts.userId
+ + " isCeDatabaseAttached=" + accounts.openHelper.isCeDatabaseAttached()
+ + " userLocked=" + mUnlockedUsers.get(accounts.userId));
+ }
if (invalidateAuthenticatorCache) {
mAuthenticatorCache.invalidateCache(accounts.userId);
}
@@ -453,8 +472,7 @@
null, null, null, null, ACCOUNTS_ID);
try {
accounts.accountCache.clear();
- final HashMap<String, ArrayList<String>> accountNamesByType =
- new LinkedHashMap<String, ArrayList<String>>();
+ final HashMap<String, ArrayList<String>> accountNamesByType = new LinkedHashMap<>();
while (cursor.moveToNext()) {
final long accountId = cursor.getLong(0);
final String accountType = cursor.getString(1);
@@ -482,15 +500,12 @@
accountNames.add(accountName);
}
}
- for (Map.Entry<String, ArrayList<String>> cur
- : accountNamesByType.entrySet()) {
+ for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
final String accountType = cur.getKey();
final ArrayList<String> accountNames = cur.getValue();
final Account[] accountsForType = new Account[accountNames.size()];
- int i = 0;
- for (String accountName : accountNames) {
- accountsForType[i] = new Account(accountName, accountType);
- ++i;
+ for (int i = 0; i < accountsForType.length; i++) {
+ accountsForType[i] = new Account(accountNames.get(i), accountType);
}
accounts.accountCache.put(accountType, accountsForType);
}
@@ -522,12 +537,25 @@
protected UserAccounts getUserAccounts(int userId) {
synchronized (mUsers) {
UserAccounts accounts = mUsers.get(userId);
+ boolean validateAccounts = false;
if (accounts == null) {
accounts = new UserAccounts(mContext, userId);
initializeDebugDbSizeAndCompileSqlStatementForLogging(
accounts.openHelper.getWritableDatabase(), accounts);
mUsers.append(userId, accounts);
purgeOldGrants(accounts);
+ validateAccounts = true;
+ }
+ // open CE database if necessary
+ if (!accounts.openHelper.isCeDatabaseAttached() && mUnlockedUsers.get(userId)) {
+ Log.i(TAG, "User " + userId + " is unlocked - opening CE database");
+ synchronized (accounts.cacheLock) {
+ CeDatabaseHelper.create(mContext, userId);
+ accounts.openHelper.attachCeDatabase();
+ }
+ // TODO Synchronize accounts by removing CE account not available in DE
+ }
+ if (validateAccounts) {
validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
}
return accounts;
@@ -571,27 +599,51 @@
if (userId < 1) return;
UserAccounts accounts;
+ boolean userUnlocked;
synchronized (mUsers) {
accounts = mUsers.get(userId);
mUsers.remove(userId);
+ userUnlocked = mUnlockedUsers.get(userId);
+ mUnlockedUsers.delete(userId);
}
- if (accounts == null) {
- File dbFile = new File(getDatabaseName(userId));
- dbFile.delete();
- return;
+ if (accounts != null) {
+ synchronized (accounts.cacheLock) {
+ accounts.openHelper.close();
+ }
}
+ Log.i(TAG, "Removing database files for user " + userId);
+ File dbFile = new File(getDeDatabaseName(userId));
- synchronized (accounts.cacheLock) {
- accounts.openHelper.close();
- File dbFile = new File(getDatabaseName(userId));
- dbFile.delete();
+ deleteDbFileWarnIfFailed(dbFile);
+ // Remove CE file if user is unlocked, or FBE is not enabled
+ boolean fbeEnabled = StorageManager.isFileEncryptedNativeOrEmulated();
+ if (!fbeEnabled || userUnlocked) {
+ File ceDb = new File(getCeDatabaseName(userId));
+ if (ceDb.exists()) {
+ deleteDbFileWarnIfFailed(ceDb);
+ }
+ }
+ }
+
+ private static void deleteDbFileWarnIfFailed(File dbFile) {
+ if (!SQLiteDatabase.deleteDatabase(dbFile)) {
+ Log.w(TAG, "Database at " + dbFile + " was not deleted successfully");
}
}
private void onUserUnlocked(Intent intent) {
int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "onUserUnlocked " + userId);
+ }
+ synchronized (mUsers) {
+ mUnlockedUsers.put(userId, true);
+ }
if (userId < 1) return;
+ syncSharedAccounts(userId);
+ }
+ private void syncSharedAccounts(int userId) {
// Check if there's a shared account that needs to be created as an account
Account[] sharedAccounts = getSharedAccountsAsUser(userId);
if (sharedAccounts == null || sharedAccounts.length == 0) return;
@@ -645,20 +697,15 @@
if (account == null) {
return null;
}
+ if (!isUserUnlocked(accounts.userId)) {
+ Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked");
+ return null;
+ }
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
- Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
- ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
- new String[]{account.name, account.type}, null, null, null);
- try {
- if (cursor.moveToNext()) {
- return cursor.getString(0);
- }
- return null;
- } finally {
- cursor.close();
- }
+ final SQLiteDatabase db = accounts.openHelper.getReadableDatabaseUserIsUnlocked();
+ return CeDatabaseHelper.findAccountPasswordByNameAndType(db, account.name,
+ account.type);
}
}
@@ -699,7 +746,7 @@
try {
if (cursor.moveToNext()) {
String previousName = cursor.getString(0);
- previousNameRef = new AtomicReference<String>(previousName);
+ previousNameRef = new AtomicReference<>(previousName);
accounts.previousNameCache.put(account, previousNameRef);
return previousName;
} else {
@@ -735,7 +782,12 @@
long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
- return readUserDataInternal(accounts, account, key);
+ synchronized (accounts.cacheLock) {
+ if (!accountExistsCacheLocked(accounts, account)) {
+ return null;
+ }
+ return readUserDataInternalLocked(accounts, account, key);
+ }
} finally {
restoreCallingIdentity(identityToken);
}
@@ -825,7 +877,7 @@
long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
- return addAccountInternal(accounts, account, password, extras, false, callingUid);
+ return addAccountInternal(accounts, account, password, extras, callingUid);
} finally {
restoreCallingIdentity(identityToken);
}
@@ -999,17 +1051,22 @@
}
private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
- Bundle extras, boolean restricted, int callingUid) {
+ Bundle extras, int callingUid) {
Bundle.setDefusable(extras, true);
if (account == null) {
return false;
}
+ if (!isUserUnlocked(accounts.userId)) {
+ Log.w(TAG, "Account " + account + " cannot be added - user " + accounts.userId
+ + " is locked. callingUid=" + callingUid);
+ return false;
+ }
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+ final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
db.beginTransaction();
try {
long numMatches = DatabaseUtils.longForQuery(db,
- "select count(*) from " + TABLE_ACCOUNTS
+ "select count(*) from " + CE_TABLE_ACCOUNTS
+ " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
new String[]{account.name, account.type});
if (numMatches > 0) {
@@ -1021,13 +1078,24 @@
values.put(ACCOUNTS_NAME, account.name);
values.put(ACCOUNTS_TYPE, account.type);
values.put(ACCOUNTS_PASSWORD, password);
- values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS, System.currentTimeMillis());
- long accountId = db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
+ long accountId = db.insert(CE_TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
if (accountId < 0) {
Log.w(TAG, "insertAccountIntoDatabase: " + account
+ ", skipping the DB insert failed");
return false;
}
+ // Insert into DE table
+ values = new ContentValues();
+ values.put(ACCOUNTS_ID, accountId);
+ values.put(ACCOUNTS_NAME, account.name);
+ values.put(ACCOUNTS_TYPE, account.type);
+ values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS,
+ System.currentTimeMillis());
+ if (db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values) < 0) {
+ Log.w(TAG, "insertAccountIntoDatabase: " + account
+ + ", skipping the DB insert failed");
+ return false;
+ }
if (extras != null) {
for (String key : extras.keySet()) {
final String value = extras.getString(key);
@@ -1055,6 +1123,12 @@
return true;
}
+ private boolean isUserUnlocked(int userId) {
+ synchronized (mUsers) {
+ return mUnlockedUsers.get(userId);
+ }
+ }
+
/**
* Adds the account to all linked restricted users as shared accounts. If the user is currently
* running, then clone the account too.
@@ -1079,7 +1153,7 @@
values.put(EXTRAS_KEY, key);
values.put(EXTRAS_ACCOUNTS_ID, accountId);
values.put(EXTRAS_VALUE, value);
- return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
+ return db.insert(CE_TABLE_EXTRAS, EXTRAS_KEY, values);
}
@Override
@@ -1226,17 +1300,19 @@
}
}
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+ final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
db.beginTransaction();
boolean isSuccessful = false;
Account renamedAccount = new Account(newName, accountToRename.type);
try {
- final ContentValues values = new ContentValues();
- values.put(ACCOUNTS_NAME, newName);
- values.put(ACCOUNTS_PREVIOUS_NAME, accountToRename.name);
final long accountId = getAccountIdLocked(db, accountToRename);
if (accountId >= 0) {
+ final ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_NAME, newName);
final String[] argsAccountId = { String.valueOf(accountId) };
+ db.update(CE_TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
+ // Update NAME/PREVIOUS_NAME in DE accounts table
+ values.put(ACCOUNTS_PREVIOUS_NAME, accountToRename.name);
db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
db.setTransactionSuccessful();
isSuccessful = true;
@@ -1332,7 +1408,7 @@
* authenticator. This will let users remove accounts (via Settings in the system) but not
* arbitrary applications (like competing authenticators).
*/
- UserHandle user = new UserHandle(userId);
+ UserHandle user = UserHandle.of(userId);
if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
&& !isSystemUid(callingUid)) {
String msg = String.format(
@@ -1467,13 +1543,17 @@
}
private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
+ // For now user is required to be unlocked. TODO: Handle both cases in the future
int deleted;
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+ final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
final long accountId = getAccountIdLocked(db, account);
deleted = db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE
+ "=?",
new String[]{account.name, account.type});
+ // Delete from CE table
+ db.delete(CE_TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
+ new String[]{account.name, account.type});
removeAccountFromCacheLocked(accounts, account);
sendAccountsChangedBroadcast(accounts.userId);
@@ -1512,7 +1592,7 @@
try {
UserAccounts accounts = getUserAccounts(userId);
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+ final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
db.beginTransaction();
try {
invalidateAuthTokenLocked(accounts, db, accountType, authToken);
@@ -1544,22 +1624,22 @@
return;
}
Cursor cursor = db.rawQuery(
- "SELECT " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
- + ", " + TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
- + ", " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
- + " FROM " + TABLE_ACCOUNTS
- + " JOIN " + TABLE_AUTHTOKENS
- + " ON " + TABLE_ACCOUNTS + "." + ACCOUNTS_ID
- + " = " + AUTHTOKENS_ACCOUNTS_ID
- + " WHERE " + AUTHTOKENS_AUTHTOKEN + " = ? AND "
- + TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
+ "SELECT " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
+ + ", " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
+ + ", " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
+ + " FROM " + CE_TABLE_ACCOUNTS
+ + " JOIN " + CE_TABLE_AUTHTOKENS
+ + " ON " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_ID
+ + " = " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_ACCOUNTS_ID
+ + " WHERE " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_AUTHTOKEN
+ + " = ? AND " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
new String[]{authToken, accountType});
try {
while (cursor.moveToNext()) {
long authTokenId = cursor.getLong(0);
String accountName = cursor.getString(1);
String authTokenType = cursor.getString(2);
- db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
+ db.delete(CE_TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
writeAuthTokenIntoCacheLocked(
accounts,
db,
@@ -1585,7 +1665,7 @@
return;
}
cancelNotification(getSigninRequiredNotificationId(accounts, account),
- new UserHandle(accounts.userId));
+ UserHandle.of(accounts.userId));
synchronized (accounts.cacheLock) {
accounts.accountTokenCaches.put(
account, token, tokenType, callerPkg, callerSigDigest, expiryMillis);
@@ -1598,23 +1678,23 @@
return false;
}
cancelNotification(getSigninRequiredNotificationId(accounts, account),
- new UserHandle(accounts.userId));
+ UserHandle.of(accounts.userId));
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+ final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
db.beginTransaction();
try {
long accountId = getAccountIdLocked(db, account);
if (accountId < 0) {
return false;
}
- db.delete(TABLE_AUTHTOKENS,
+ db.delete(CE_TABLE_AUTHTOKENS,
AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
new String[]{type});
ContentValues values = new ContentValues();
values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
values.put(AUTHTOKENS_TYPE, type);
values.put(AUTHTOKENS_AUTHTOKEN, authToken);
- if (db.insert(TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
+ if (db.insert(CE_TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
db.setTransactionSuccessful();
writeAuthTokenIntoCacheLocked(accounts, db, account, type, authToken);
return true;
@@ -1714,7 +1794,7 @@
return;
}
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+ final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
db.beginTransaction();
try {
final ContentValues values = new ContentValues();
@@ -1722,8 +1802,8 @@
final long accountId = getAccountIdLocked(db, account);
if (accountId >= 0) {
final String[] argsAccountId = {String.valueOf(accountId)};
- db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
- db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
+ db.update(CE_TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
+ db.delete(CE_TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
accounts.authTokenCache.remove(account);
accounts.accountTokenCaches.remove(account);
db.setTransactionSuccessful();
@@ -1794,44 +1874,57 @@
long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
- setUserdataInternal(accounts, account, key, value);
+ synchronized (accounts.cacheLock) {
+ if (!accountExistsCacheLocked(accounts, account)) {
+ return;
+ }
+ setUserdataInternalLocked(accounts, account, key, value);
+ }
} finally {
restoreCallingIdentity(identityToken);
}
}
- private void setUserdataInternal(UserAccounts accounts, Account account, String key,
+ private boolean accountExistsCacheLocked(UserAccounts accounts, Account account) {
+ if (accounts.accountCache.containsKey(account.type)) {
+ for (Account acc : accounts.accountCache.get(account.type)) {
+ if (acc.name.equals(account.name)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private void setUserdataInternalLocked(UserAccounts accounts, Account account, String key,
String value) {
if (account == null || key == null) {
return;
}
- synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
- db.beginTransaction();
- try {
- long accountId = getAccountIdLocked(db, account);
- if (accountId < 0) {
+ final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ long accountId = getAccountIdLocked(db, account);
+ if (accountId < 0) {
+ return;
+ }
+ long extrasId = getExtrasIdLocked(db, accountId, key);
+ if (extrasId < 0) {
+ extrasId = insertExtraLocked(db, accountId, key, value);
+ if (extrasId < 0) {
return;
}
- long extrasId = getExtrasIdLocked(db, accountId, key);
- if (extrasId < 0 ) {
- extrasId = insertExtraLocked(db, accountId, key, value);
- if (extrasId < 0) {
- return;
- }
- } else {
- ContentValues values = new ContentValues();
- values.put(EXTRAS_VALUE, value);
- if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
- return;
- }
-
+ } else {
+ ContentValues values = new ContentValues();
+ values.put(EXTRAS_VALUE, value);
+ if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
+ return;
}
- writeUserDataIntoCacheLocked(accounts, db, account, key, value);
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
}
+ writeUserDataIntoCacheLocked(accounts, db, account, key, value);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
}
}
@@ -2425,21 +2518,31 @@
userId);
return;
}
-
final int pid = Binder.getCallingPid();
final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
options.putInt(AccountManager.KEY_CALLER_UID, uid);
options.putInt(AccountManager.KEY_CALLER_PID, pid);
+ // Check to see if the Password should be included to the caller.
+ String callerPkg = optionsIn.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
+ boolean isPasswordForwardingAllowed = isPermitted(
+ callerPkg, uid, Manifest.permission.GET_PASSWORD_PRIVILEGED);
+
int usrId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(usrId);
logRecordWithUid(accounts, DebugDbHelper.ACTION_CALLED_START_ACCOUNT_ADD,
TABLE_ACCOUNTS, uid);
- new StartAccountSession(accounts, response, accountType, expectActivityLaunch,
- null /* accountName */, false /* authDetailsRequired */,
- true /* updateLastAuthenticationTime */) {
+ new StartAccountSession(
+ accounts,
+ response,
+ accountType,
+ expectActivityLaunch,
+ null /* accountName */,
+ false /* authDetailsRequired */,
+ true /* updateLastAuthenticationTime */,
+ isPasswordForwardingAllowed) {
@Override
public void run() throws RemoteException {
mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType,
@@ -2462,12 +2565,21 @@
/** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */
private abstract class StartAccountSession extends Session {
- public StartAccountSession(UserAccounts accounts, IAccountManagerResponse response,
- String accountType, boolean expectActivityLaunch, String accountName,
- boolean authDetailsRequired, boolean updateLastAuthenticationTime) {
+ private final boolean mIsPasswordForwardingAllowed;
+
+ public StartAccountSession(
+ UserAccounts accounts,
+ IAccountManagerResponse response,
+ String accountType,
+ boolean expectActivityLaunch,
+ String accountName,
+ boolean authDetailsRequired,
+ boolean updateLastAuthenticationTime,
+ boolean isPasswordForwardingAllowed) {
super(accounts, response, accountType, expectActivityLaunch,
true /* stripAuthTokenFromResult */, accountName, authDetailsRequired,
updateLastAuthenticationTime);
+ mIsPasswordForwardingAllowed = isPasswordForwardingAllowed;
}
@Override
@@ -2480,6 +2592,10 @@
checkKeyIntent(
Binder.getCallingUid(),
intent);
+ // Omit passwords if the caller isn't permitted to see them.
+ if (!mIsPasswordForwardingAllowed) {
+ result.remove(AccountManager.KEY_PASSWORD);
+ }
}
IAccountManagerResponse response;
if (mExpectActivityLaunch && result != null
@@ -2826,6 +2942,12 @@
}
int userId = UserHandle.getCallingUserId();
+
+ // Check to see if the Password should be included to the caller.
+ String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
+ boolean isPasswordForwardingAllowed = isPermitted(
+ callerPkg, uid, Manifest.permission.GET_PASSWORD_PRIVILEGED);
+
long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
@@ -2836,7 +2958,8 @@
expectActivityLaunch,
account.name,
false /* authDetailsRequired */,
- true /* updateLastCredentialTime */) {
+ true /* updateLastCredentialTime */,
+ isPasswordForwardingAllowed) {
@Override
public void run() throws RemoteException {
mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType,
@@ -3307,7 +3430,6 @@
long sharedTableAccountId = getAccountIdFromSharedTable(db, account);
final ContentValues values = new ContentValues();
values.put(ACCOUNTS_NAME, newName);
- values.put(ACCOUNTS_PREVIOUS_NAME, account.name);
int r = db.update(
TABLE_SHARED_ACCOUNTS,
values,
@@ -3347,7 +3469,7 @@
public Account[] getSharedAccountsAsUser(int userId) {
userId = handleIncomingUser(userId);
UserAccounts accounts = getUserAccounts(userId);
- ArrayList<Account> accountList = new ArrayList<Account>();
+ ArrayList<Account> accountList = new ArrayList<>();
Cursor cursor = null;
try {
cursor = accounts.openHelper.getReadableDatabase()
@@ -3488,7 +3610,7 @@
}
private long getExtrasIdLocked(SQLiteDatabase db, long accountId, String key) {
- Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_ID},
+ Cursor cursor = db.query(CE_TABLE_EXTRAS, new String[]{EXTRAS_ID},
EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
new String[]{key}, null, null, null);
try {
@@ -3729,8 +3851,8 @@
if (accountPresent) {
lastAuthenticatedTime = DatabaseUtils.longForQuery(
mAccounts.openHelper.getReadableDatabase(),
- "select " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
- + " from " +
+ "SELECT " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
+ + " FROM " +
TABLE_ACCOUNTS + " WHERE " + ACCOUNTS_NAME + "=? AND "
+ ACCOUNTS_TYPE + "=?",
new String[] {
@@ -3859,7 +3981,7 @@
Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
}
if (!mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
- new UserHandle(mAccounts.userId))) {
+ UserHandle.of(mAccounts.userId))) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
}
@@ -3893,15 +4015,16 @@
}
}
- private static String getDatabaseName(int userId) {
+ static String getPreNDatabaseName(int userId) {
File systemDir = Environment.getDataSystemDirectory();
- File databaseFile = new File(Environment.getUserSystemDirectory(userId), DATABASE_NAME);
+ File databaseFile = new File(Environment.getUserSystemDirectory(userId),
+ PRE_N_DATABASE_NAME);
if (userId == 0) {
// Migrate old file, if it exists, to the new location.
// Make sure the new file doesn't already exist. A dummy file could have been
// accidentally created in the old location, causing the new one to become corrupted
// as well.
- File oldFile = new File(systemDir, DATABASE_NAME);
+ File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
if (oldFile.exists() && !databaseFile.exists()) {
// Check for use directory; create if it doesn't exist, else renameTo will fail
File userDir = Environment.getUserSystemDirectory(userId);
@@ -3918,6 +4041,18 @@
return databaseFile.getPath();
}
+ static String getDeDatabaseName(int userId) {
+ File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
+ DE_DATABASE_NAME);
+ return databaseFile.getPath();
+ }
+
+ static String getCeDatabaseName(int userId) {
+ File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
+ CE_DATABASE_NAME);
+ return databaseFile.getPath();
+ }
+
private static class DebugDbHelper{
private DebugDbHelper() {
}
@@ -4050,58 +4185,22 @@
return DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
}
- static class DatabaseHelper extends SQLiteOpenHelper {
+ static class PreNDatabaseHelper extends SQLiteOpenHelper {
private final Context mContext;
private final int mUserId;
- public DatabaseHelper(Context context, int userId) {
- super(context, AccountManagerService.getDatabaseName(userId), null, DATABASE_VERSION);
+ public PreNDatabaseHelper(Context context, int userId) {
+ super(context, AccountManagerService.getPreNDatabaseName(userId), null,
+ PRE_N_DATABASE_VERSION);
mContext = context;
mUserId = userId;
}
- /**
- * This call needs to be made while the mCacheLock is held. The way to
- * ensure this is to get the lock any time a method is called ont the DatabaseHelper
- * @param db The database.
- */
@Override
public void onCreate(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
- + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
- + ACCOUNTS_NAME + " TEXT NOT NULL, "
- + ACCOUNTS_TYPE + " TEXT NOT NULL, "
- + ACCOUNTS_PASSWORD + " TEXT, "
- + ACCOUNTS_PREVIOUS_NAME + " TEXT, "
- + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " INTEGER DEFAULT 0, "
- + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
-
- db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " ( "
- + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
- + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
- + AUTHTOKENS_TYPE + " TEXT NOT NULL, "
- + AUTHTOKENS_AUTHTOKEN + " TEXT, "
- + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
-
- createGrantsTable(db);
-
- db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
- + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
- + EXTRAS_ACCOUNTS_ID + " INTEGER, "
- + EXTRAS_KEY + " TEXT NOT NULL, "
- + EXTRAS_VALUE + " TEXT, "
- + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
-
- db.execSQL("CREATE TABLE " + TABLE_META + " ( "
- + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
- + META_VALUE + " TEXT)");
-
- createSharedAccountsTable(db);
-
- createAccountsDeletionTrigger(db);
-
- DebugDbHelper.createDebugTable(db);
+ // We use PreNDatabaseHelper only if pre-N db exists
+ throw new IllegalStateException("Legacy database cannot be created - only upgraded!");
}
private void createSharedAccountsTable(SQLiteDatabase db) {
@@ -4161,6 +4260,9 @@
}
}
+ /**
+ * Pre-N database may need an upgrade before splitting
+ */
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
@@ -4222,6 +4324,315 @@
}
}
+ static class DeDatabaseHelper extends SQLiteOpenHelper {
+
+ private final int mUserId;
+ private volatile boolean mCeAttached;
+
+ private DeDatabaseHelper(Context context, int userId) {
+ super(context, getDeDatabaseName(userId), null, DE_DATABASE_VERSION);
+ mUserId = userId;
+ }
+
+ /**
+ * This call needs to be made while the mCacheLock is held. The way to
+ * ensure this is to get the lock any time a method is called ont the DatabaseHelper
+ * @param db The database.
+ */
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ Log.i(TAG, "Creating DE database for user " + mUserId);
+ db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
+ + ACCOUNTS_ID + " INTEGER PRIMARY KEY, "
+ + ACCOUNTS_NAME + " TEXT NOT NULL, "
+ + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+ + ACCOUNTS_PREVIOUS_NAME + " TEXT, "
+ + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " INTEGER DEFAULT 0, "
+ + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+
+ db.execSQL("CREATE TABLE " + TABLE_META + " ( "
+ + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
+ + META_VALUE + " TEXT)");
+
+ createGrantsTable(db);
+ createSharedAccountsTable(db);
+ createAccountsDeletionTrigger(db);
+ DebugDbHelper.createDebugTable(db);
+ }
+
+ private void createSharedAccountsTable(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + TABLE_SHARED_ACCOUNTS + " ( "
+ + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + ACCOUNTS_NAME + " TEXT NOT NULL, "
+ + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+ + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+ }
+
+ private void createAccountsDeletionTrigger(SQLiteDatabase db) {
+ db.execSQL(""
+ + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
+ + " BEGIN"
+ + " DELETE FROM " + TABLE_GRANTS
+ + " WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+ + " END");
+ }
+
+ private void createGrantsTable(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + TABLE_GRANTS + " ( "
+ + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
+ + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL, "
+ + GRANTS_GRANTEE_UID + " INTEGER NOT NULL, "
+ + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
+ + "," + GRANTS_GRANTEE_UID + "))");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ Log.i(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
+
+ if (oldVersion != newVersion) {
+ Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
+ }
+ }
+
+ public void attachCeDatabase() {
+ File ceDbFile = new File(getCeDatabaseName(mUserId));
+ SQLiteDatabase db = getWritableDatabase();
+ db.execSQL("ATTACH DATABASE '" + ceDbFile.getPath()+ "' AS ceDb");
+ mCeAttached = true;
+ }
+
+ public boolean isCeDatabaseAttached() {
+ return mCeAttached;
+ }
+
+
+ public SQLiteDatabase getReadableDatabaseUserIsUnlocked() {
+ if(!mCeAttached) {
+ Log.wtf(TAG, "getReadableDatabaseUserIsUnlocked called while user "
+ + mUserId + " is still locked ", new Throwable());
+ }
+ return super.getReadableDatabase();
+ }
+
+ public SQLiteDatabase getWritableDatabaseUserIsUnlocked() {
+ if(!mCeAttached) {
+ Log.wtf(TAG, "getWritableDatabaseUserIsUnlocked called while user " + mUserId
+ + " is still locked ", new Throwable());
+ }
+ return super.getWritableDatabase();
+ }
+
+ @Override
+ public void onOpen(SQLiteDatabase db) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DE_DATABASE_NAME);
+ }
+
+ private void migratePreNDbToDe(File preNDbFile) {
+ Log.i(TAG, "Migrate pre-N database to DE preNDbFile=" + preNDbFile);
+ SQLiteDatabase db = getWritableDatabase();
+ db.execSQL("ATTACH DATABASE '" + preNDbFile.getPath() + "' AS preNDb");
+ db.beginTransaction();
+ // Copy accounts fields
+ db.execSQL("INSERT INTO " + TABLE_ACCOUNTS
+ + "(" + ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ", "
+ + ACCOUNTS_PREVIOUS_NAME + ", " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
+ + ") "
+ + "SELECT " + ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ", "
+ + ACCOUNTS_PREVIOUS_NAME + ", " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
+ + " FROM preNDb." + TABLE_ACCOUNTS);
+ // Copy SHARED_ACCOUNTS
+ db.execSQL("INSERT INTO " + TABLE_SHARED_ACCOUNTS
+ + "(" + SHARED_ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ") " +
+ "SELECT " + SHARED_ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE
+ + " FROM preNDb." + TABLE_SHARED_ACCOUNTS);
+ // Copy DEBUG_TABLE
+ db.execSQL("INSERT INTO " + DebugDbHelper.TABLE_DEBUG
+ + "(" + ACCOUNTS_ID + "," + DebugDbHelper.ACTION_TYPE + ","
+ + DebugDbHelper.TIMESTAMP + "," + DebugDbHelper.CALLER_UID + ","
+ + DebugDbHelper.TABLE_NAME + "," + DebugDbHelper.KEY + ") " +
+ "SELECT " + ACCOUNTS_ID + "," + DebugDbHelper.ACTION_TYPE + ","
+ + DebugDbHelper.TIMESTAMP + "," + DebugDbHelper.CALLER_UID + ","
+ + DebugDbHelper.TABLE_NAME + "," + DebugDbHelper.KEY
+ + " FROM preNDb." + DebugDbHelper.TABLE_DEBUG);
+ // Copy GRANTS
+ db.execSQL("INSERT INTO " + TABLE_GRANTS
+ + "(" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE + ","
+ + GRANTS_GRANTEE_UID + ") " +
+ "SELECT " + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE + ","
+ + GRANTS_GRANTEE_UID + " FROM preNDb." + TABLE_GRANTS);
+ // Copy META
+ db.execSQL("INSERT INTO " + TABLE_META
+ + "(" + META_KEY + "," + META_VALUE + ") "
+ + "SELECT " + META_KEY + "," + META_VALUE + " FROM preNDb." + TABLE_META);
+ db.setTransactionSuccessful();
+ db.endTransaction();
+
+ db.execSQL("DETACH DATABASE preNDb");
+ }
+
+ static DeDatabaseHelper create(Context context, int userId) {
+ File oldDb = new File(getPreNDatabaseName(userId));
+ File newDb = new File(getDeDatabaseName(userId));
+ boolean newDbExists = newDb.exists();
+ DeDatabaseHelper deDatabaseHelper = new DeDatabaseHelper(context, userId);
+ // If the db just created, and there is a legacy db, migrate it
+ if (!newDbExists && oldDb.exists()) {
+ // Migrate legacy db to the latest version - PRE_N_DATABASE_VERSION
+ PreNDatabaseHelper preNDatabaseHelper = new PreNDatabaseHelper(context, userId);
+ // Open the database to force upgrade if required
+ preNDatabaseHelper.getWritableDatabase();
+ preNDatabaseHelper.close();
+ // Move data without SPII to DE
+ deDatabaseHelper.migratePreNDbToDe(oldDb);
+ }
+ return deDatabaseHelper;
+ }
+ }
+
+ static class CeDatabaseHelper extends SQLiteOpenHelper {
+
+ public CeDatabaseHelper(Context context, int userId) {
+ super(context, getCeDatabaseName(userId), null, CE_DATABASE_VERSION);
+ }
+
+ /**
+ * This call needs to be made while the mCacheLock is held.
+ * @param db The database.
+ */
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ Log.i(TAG, "Creating CE database " + getDatabaseName());
+ db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
+ + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + ACCOUNTS_NAME + " TEXT NOT NULL, "
+ + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+ + ACCOUNTS_PASSWORD + " TEXT, "
+ + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+
+ db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " ( "
+ + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
+ + AUTHTOKENS_TYPE + " TEXT NOT NULL, "
+ + AUTHTOKENS_AUTHTOKEN + " TEXT, "
+ + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
+
+ db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
+ + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + EXTRAS_ACCOUNTS_ID + " INTEGER, "
+ + EXTRAS_KEY + " TEXT NOT NULL, "
+ + EXTRAS_VALUE + " TEXT, "
+ + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
+
+ createAccountsDeletionTrigger(db);
+ }
+
+ private void createAccountsDeletionTrigger(SQLiteDatabase db) {
+ db.execSQL(""
+ + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
+ + " BEGIN"
+ + " DELETE FROM " + TABLE_AUTHTOKENS
+ + " WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+ + " DELETE FROM " + TABLE_EXTRAS
+ + " WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+ + " END");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ Log.i(TAG, "Upgrade CE from version " + oldVersion + " to version " + newVersion);
+
+ if (oldVersion == 9) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "onUpgrade upgrading to v10");
+ }
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_META);
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_SHARED_ACCOUNTS);
+ // Recreate the trigger, since the old one references the table to be removed
+ db.execSQL("DROP TRIGGER IF EXISTS " + TABLE_ACCOUNTS + "Delete");
+ createAccountsDeletionTrigger(db);
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_GRANTS);
+ db.execSQL("DROP TABLE IF EXISTS " + DebugDbHelper.TABLE_DEBUG);
+ oldVersion ++;
+ }
+
+ if (oldVersion != newVersion) {
+ Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
+ }
+ }
+
+ @Override
+ public void onOpen(SQLiteDatabase db) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + CE_DATABASE_NAME);
+ }
+
+ static String findAccountPasswordByNameAndType(SQLiteDatabase db, String name,
+ String type) {
+ Cursor cursor = db.query(CE_TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
+ ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
+ new String[]{name, type}, null, null, null);
+ try {
+ if (cursor.moveToNext()) {
+ return cursor.getString(0);
+ }
+ return null;
+ } finally {
+ cursor.close();
+ }
+ }
+
+ /**
+ * Creates a new {@code CeDatabaseHelper}. If pre-N db file is present at the old location,
+ * it also performs migration to the new CE database.
+ * @param context
+ * @param userId id of the user where the database is located
+ */
+ static CeDatabaseHelper create(Context context, int userId) {
+
+ File oldDatabaseFile = new File(getPreNDatabaseName(userId));
+ File ceDatabaseFile = new File(getCeDatabaseName(userId));
+ boolean newDbExists = ceDatabaseFile.exists();
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "CeDatabaseHelper.create userId=" + userId + " oldDbExists="
+ + oldDatabaseFile.exists() + " newDbExists=" + newDbExists);
+ }
+ boolean removeOldDb = false;
+ if (!newDbExists && oldDatabaseFile.exists()) {
+ removeOldDb = migratePreNDbToCe(oldDatabaseFile, ceDatabaseFile);
+ }
+ // Try to open and upgrade if necessary
+ CeDatabaseHelper ceHelper = new CeDatabaseHelper(context, userId);
+ ceHelper.getWritableDatabase();
+ ceHelper.close();
+ if (removeOldDb) {
+ // TODO STOPSHIP - backup file during testing. Remove file before the release
+ Log.i(TAG, "Migration complete - creating backup of old db " + oldDatabaseFile);
+ renameToBakFile(oldDatabaseFile);
+ }
+ return ceHelper;
+ }
+
+ private static void renameToBakFile(File file) {
+ File bakFile = new File(file.getPath() + ".bak");
+ if (!file.renameTo(bakFile)) {
+ Log.e(TAG, "Cannot move file to " + bakFile);
+ }
+ }
+
+ private static boolean migratePreNDbToCe(File oldDbFile, File ceDbFile) {
+ Log.i(TAG, "Moving pre-N DB " + oldDbFile + " to CE " + ceDbFile);
+ try {
+ FileUtils.copyFileOrThrow(oldDbFile, ceDbFile);
+ } catch (IOException e) {
+ Log.e(TAG, "Cannot copy file to " + ceDbFile + " from " + oldDbFile, e);
+ // Try to remove potentially damaged file if I/O error occurred
+ deleteDbFileWarnIfFailed(ceDbFile);
+ return false;
+ }
+ return true;
+ }
+ }
+
public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
return asBinder();
}
@@ -4666,7 +5077,7 @@
db.endTransaction();
}
cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
- new UserHandle(accounts.userId));
+ UserHandle.of(accounts.userId));
}
}
@@ -4891,7 +5302,7 @@
HashMap<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
if (authTokensForAccount == null) {
// need to populate the cache for this account
- final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
+ final SQLiteDatabase db = accounts.openHelper.getReadableDatabaseUserIsUnlocked();
authTokensForAccount = readAuthTokensForAccountFromDatabaseLocked(db, account);
accounts.authTokenCache.put(account, authTokensForAccount);
}
@@ -4899,23 +5310,22 @@
}
}
- protected String readUserDataInternal(UserAccounts accounts, Account account, String key) {
- synchronized (accounts.cacheLock) {
- HashMap<String, String> userDataForAccount = accounts.userDataCache.get(account);
- if (userDataForAccount == null) {
- // need to populate the cache for this account
- final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
- userDataForAccount = readUserDataForAccountFromDatabaseLocked(db, account);
- accounts.userDataCache.put(account, userDataForAccount);
- }
- return userDataForAccount.get(key);
+ protected String readUserDataInternalLocked(
+ UserAccounts accounts, Account account, String key) {
+ HashMap<String, String> userDataForAccount = accounts.userDataCache.get(account);
+ if (userDataForAccount == null) {
+ // need to populate the cache for this account
+ final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
+ userDataForAccount = readUserDataForAccountFromDatabaseLocked(db, account);
+ accounts.userDataCache.put(account, userDataForAccount);
}
+ return userDataForAccount.get(key);
}
protected HashMap<String, String> readUserDataForAccountFromDatabaseLocked(
final SQLiteDatabase db, Account account) {
- HashMap<String, String> userDataForAccount = new HashMap<String, String>();
- Cursor cursor = db.query(TABLE_EXTRAS,
+ HashMap<String, String> userDataForAccount = new HashMap<>();
+ Cursor cursor = db.query(CE_TABLE_EXTRAS,
COLUMNS_EXTRAS_KEY_AND_VALUE,
SELECTION_USERDATA_BY_ACCOUNT,
new String[]{account.name, account.type},
@@ -4934,8 +5344,8 @@
protected HashMap<String, String> readAuthTokensForAccountFromDatabaseLocked(
final SQLiteDatabase db, Account account) {
- HashMap<String, String> authTokensForAccount = new HashMap<String, String>();
- Cursor cursor = db.query(TABLE_AUTHTOKENS,
+ HashMap<String, String> authTokensForAccount = new HashMap<>();
+ Cursor cursor = db.query(CE_TABLE_AUTHTOKENS,
COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN,
SELECTION_AUTHTOKENS_BY_ACCOUNT,
new String[]{account.name, account.type},
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index f99caba..5d1cb8a 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -343,6 +343,25 @@
return null;
}
+ if (!r.startRequested) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ // Before going further -- if this app is not allowed to run in the
+ // background, then at this point we aren't going to let it period.
+ final int allowed = mAm.checkAllowBackgroundLocked(
+ r.appInfo.uid, r.packageName, callingPid, true);
+ if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
+ Slog.w(TAG, "Background start not allowed: service "
+ + service + " to " + r.name.flattenToShortString()
+ + " from pid=" + callingPid + " uid=" + callingUid
+ + " pkg=" + callingPackage);
+ return null;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
callingUid, r.packageName, service, service.getFlags(), null, r.userId);
@@ -940,7 +959,7 @@
}
}
- mAm.startAssociationLocked(callerApp.uid, callerApp.processName,
+ mAm.startAssociationLocked(callerApp.uid, callerApp.processName, callerApp.curProcState,
s.appInfo.uid, s.name, s.processName);
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
@@ -1274,23 +1293,6 @@
}
r = smap.mServicesByName.get(name);
if (r == null && createIfNeeded) {
- final long token = Binder.clearCallingIdentity();
- try {
- // Before going further -- if this app is not allowed to run in the
- // background, then at this point we aren't going to let it period.
- final int allowed = mAm.checkAllowBackgroundLocked(
- sInfo.applicationInfo.uid, sInfo.packageName, callingPid, true);
- if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
- Slog.w(TAG, "Background execution not allowed: service "
- + service + " to " + name.flattenToShortString()
- + " from pid=" + callingPid + " uid=" + callingUid
- + " pkg=" + callingPackage);
- return null;
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
-
Intent.FilterComparison filter
= new Intent.FilterComparison(service.cloneFilter());
ServiceRestarter res = new ServiceRestarter();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 42cf42f..f6f3295 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -891,6 +891,12 @@
int mNesting;
long mStartTime;
+ // states of the source process when the bind occurred.
+ int mLastState = ActivityManager.MAX_PROCESS_STATE + 1;
+ long mLastStateUptime;
+ long[] mStateTimes = new long[ActivityManager.MAX_PROCESS_STATE
+ - ActivityManager.MIN_PROCESS_STATE+1];
+
Association(int sourceUid, String sourceProcess, int targetUid,
ComponentName targetComponent, String targetProcess) {
mSourceUid = sourceUid;
@@ -1099,20 +1105,20 @@
ComponentName mTopComponent;
String mTopAction = Intent.ACTION_MAIN;
String mTopData;
- boolean mProcessesReady = false;
- boolean mSystemReady = false;
- boolean mBooting = false;
- boolean mCallFinishBooting = false;
- boolean mBootAnimationComplete = false;
- boolean mOnBattery = false;
- boolean mLaunchWarningShown = false;
+
+ volatile boolean mProcessesReady = false;
+ volatile boolean mSystemReady = false;
+ volatile boolean mOnBattery = false;
+ volatile int mFactoryTest;
+
+ @GuardedBy("this") boolean mBooting = false;
+ @GuardedBy("this") boolean mCallFinishBooting = false;
+ @GuardedBy("this") boolean mBootAnimationComplete = false;
+ @GuardedBy("this") boolean mLaunchWarningShown = false;
+ @GuardedBy("this") boolean mCheckedForSetup = false;
Context mContext;
- int mFactoryTest;
-
- boolean mCheckedForSetup;
-
/**
* The time at which we will allow normal application switches again,
* after a call to {@link #stopAppSwitches()}.
@@ -6056,8 +6062,7 @@
"No more processes in " + old.uidRecord);
enqueueUidChangeLocked(old.uidRecord, -1, UidRecord.CHANGE_GONE);
mActiveUids.remove(uid);
- mBatteryStatsService.noteUidProcessState(uid,
- ActivityManager.PROCESS_STATE_NONEXISTENT);
+ noteUidProcessState(uid, ActivityManager.PROCESS_STATE_NONEXISTENT);
}
old.uidRecord = null;
}
@@ -6082,7 +6087,7 @@
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
"Creating new process uid: " + uidRec);
mActiveUids.put(proc.uid, uidRec);
- mBatteryStatsService.noteUidProcessState(uidRec.uid, uidRec.curProcState);
+ noteUidProcessState(uidRec.uid, uidRec.curProcState);
enqueueUidChangeLocked(uidRec, -1, UidRecord.CHANGE_ACTIVE);
}
proc.uidRecord = uidRec;
@@ -9822,7 +9827,8 @@
public void updateLockTaskPackages(int userId, String[] packages) {
final int callingUid = Binder.getCallingUid();
if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
- throw new SecurityException("updateLockTaskPackage called from non-system process");
+ enforceCallingPermission(android.Manifest.permission.UPDATE_LOCK_TASK_PACKAGES,
+ "updateLockTaskPackages()");
}
synchronized (this) {
if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Whitelisting " + userId + ":" +
@@ -10190,7 +10196,8 @@
}
cpr.connections.add(conn);
r.conProviders.add(conn);
- startAssociationLocked(r.uid, r.processName, cpr.uid, cpr.name, cpr.info.processName);
+ startAssociationLocked(r.uid, r.processName, r.curProcState,
+ cpr.uid, cpr.name, cpr.info.processName);
return conn;
}
cpr.addExternalProcessHandleLocked(externalProcessToken);
@@ -13797,10 +13804,27 @@
TimeUtils.formatDuration(dur, pw);
pw.print(" (");
pw.print(ass.mCount);
- pw.println(" times)");
+ pw.print(" times)");
+ pw.print(" ");
+ for (int i=0; i<ass.mStateTimes.length; i++) {
+ long amt = ass.mStateTimes[i];
+ if (ass.mLastState-ActivityManager.MIN_PROCESS_STATE == i) {
+ amt += now - ass.mLastStateUptime;
+ }
+ if (amt != 0) {
+ pw.print(" ");
+ pw.print(ProcessList.makeProcStateString(
+ i + ActivityManager.MIN_PROCESS_STATE));
+ pw.print("=");
+ TimeUtils.formatDuration(amt, pw);
+ if (ass.mLastState-ActivityManager.MIN_PROCESS_STATE == i) {
+ pw.print("*");
+ }
+ }
+ }
+ pw.println();
if (ass.mNesting > 0) {
- pw.print(" ");
- pw.print(" Currently active: ");
+ pw.print(" Currently active: ");
TimeUtils.formatDuration(now - ass.mStartTime, pw);
pw.println();
}
@@ -15432,8 +15456,9 @@
}
for (int oomIndex=0; oomIndex<oomPss.length; oomIndex++) {
- if (oomAdj <= DUMP_MEM_OOM_ADJ[oomIndex]
- || oomIndex == (oomPss.length-1)) {
+ if (oomIndex == (oomPss.length - 1)
+ || (oomAdj >= DUMP_MEM_OOM_ADJ[oomIndex]
+ && oomAdj < DUMP_MEM_OOM_ADJ[oomIndex + 1])) {
oomPss[oomIndex] += myTotalPss;
oomSwapPss[oomIndex] += myTotalSwapPss;
if (oomProcs[oomIndex] == null) {
@@ -18021,6 +18046,9 @@
ActivityRecord starting, boolean initLocale, boolean persistent, int userId) {
int changes = 0;
+ if (mWindowManager != null) {
+ mWindowManager.deferSurfaceLayout();
+ }
if (values != null) {
Configuration newConfig = new Configuration(mConfiguration);
changes = newConfig.updateFrom(values);
@@ -18121,6 +18149,20 @@
null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
}
}
+ // Update the configuration with WM first and check if any of the stacks need to be
+ // resized due to the configuration change. If so, resize the stacks now and do any
+ // relaunches if necessary. This way we don't need to relaunch again below in
+ // ensureActivityConfigurationLocked().
+ if (mWindowManager != null) {
+ final int[] resizedStacks = mWindowManager.setNewConfiguration(mConfiguration);
+ if (resizedStacks != null) {
+ for (int stackId : resizedStacks) {
+ final Rect newBounds = mWindowManager.getBoundsForNewConfiguration(stackId);
+ mStackSupervisor.resizeStackLocked(
+ stackId, newBounds, null, null, false, false);
+ }
+ }
+ }
}
boolean kept = true;
@@ -18142,11 +18184,9 @@
!PRESERVE_WINDOWS);
}
}
-
- if (values != null && mWindowManager != null) {
- mWindowManager.setNewConfiguration(mConfiguration);
+ if (mWindowManager != null) {
+ mWindowManager.continueSurfaceLayout();
}
-
return kept;
}
@@ -18238,8 +18278,8 @@
return null;
}
- Association startAssociationLocked(int sourceUid, String sourceProcess, int targetUid,
- ComponentName targetComponent, String targetProcess) {
+ Association startAssociationLocked(int sourceUid, String sourceProcess, int sourceState,
+ int targetUid, ComponentName targetComponent, String targetProcess) {
if (!mTrackingAssociations) {
return null;
}
@@ -18268,7 +18308,8 @@
ass.mCount++;
ass.mNesting++;
if (ass.mNesting == 1) {
- ass.mStartTime = SystemClock.uptimeMillis();
+ ass.mStartTime = ass.mLastStateUptime = SystemClock.uptimeMillis();
+ ass.mLastState = sourceState;
}
return ass;
}
@@ -18297,7 +18338,39 @@
}
ass.mNesting--;
if (ass.mNesting == 0) {
- ass.mTime += SystemClock.uptimeMillis() - ass.mStartTime;
+ long uptime = SystemClock.uptimeMillis();
+ ass.mTime += uptime - ass.mStartTime;
+ ass.mStateTimes[ass.mLastState-ActivityManager.MIN_PROCESS_STATE]
+ += uptime - ass.mLastStateUptime;
+ ass.mLastState = ActivityManager.MAX_PROCESS_STATE + 2;
+ }
+ }
+
+ private void noteUidProcessState(final int uid, final int state) {
+ mBatteryStatsService.noteUidProcessState(uid, state);
+ if (mTrackingAssociations) {
+ for (int i1=0, N1=mAssociations.size(); i1<N1; i1++) {
+ ArrayMap<ComponentName, SparseArray<ArrayMap<String, Association>>> targetComponents
+ = mAssociations.valueAt(i1);
+ for (int i2=0, N2=targetComponents.size(); i2<N2; i2++) {
+ SparseArray<ArrayMap<String, Association>> sourceUids
+ = targetComponents.valueAt(i2);
+ ArrayMap<String, Association> sourceProcesses = sourceUids.get(uid);
+ if (sourceProcesses != null) {
+ for (int i4=0, N4=sourceProcesses.size(); i4<N4; i4++) {
+ Association ass = sourceProcesses.valueAt(i4);
+ if (ass.mNesting >= 1) {
+ // currently associated
+ long uptime = SystemClock.uptimeMillis();
+ ass.mStateTimes[ass.mLastState-ActivityManager.MIN_PROCESS_STATE]
+ += uptime - ass.mLastStateUptime;
+ ass.mLastState = state;
+ ass.mLastStateUptime = uptime;
+ }
+ }
+ }
+ }
+ }
}
}
@@ -20176,7 +20249,7 @@
}
uidRec.setProcState = uidRec.curProcState;
enqueueUidChangeLocked(uidRec, -1, uidChange);
- mBatteryStatsService.noteUidProcessState(uidRec.uid, uidRec.curProcState);
+ noteUidProcessState(uidRec.uid, uidRec.curProcState);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index d570be9..9be6b43 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -23,8 +23,6 @@
import android.os.UserHandle;
import android.util.DebugUtils;
-import com.android.internal.util.ArrayUtils;
-
import java.io.PrintWriter;
class ActivityManagerShellCommand extends ShellCommand {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index b297938..4ec1f61 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -4574,6 +4574,8 @@
}
r.configChangeFlags = 0;
+ r.deferRelaunchUntilPaused = false;
+ r.preserveWindowOnDeferredRelaunch = false;
}
boolean willActivityBeVisibleLocked(IBinder token) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 0d70e99..f659bde 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1984,6 +1984,8 @@
mTmpConfigs.clear();
mTmpInsetBounds.clear();
final ArrayList<TaskRecord> tasks = stack.getAllTasks();
+ final Rect taskBounds = tempTaskBounds != null ? tempTaskBounds : bounds;
+ final Rect insetBounds = tempTaskInsetBounds != null ? tempTaskInsetBounds : taskBounds;
for (int i = tasks.size() - 1; i >= 0; i--) {
final TaskRecord task = tasks.get(i);
if (task.isResizeable()) {
@@ -1995,9 +1997,7 @@
fitWithinBounds(tempRect2, bounds);
task.updateOverrideConfiguration(tempRect2);
} else {
- task.updateOverrideConfiguration(
- tempTaskBounds != null ? tempTaskBounds : bounds,
- tempTaskInsetBounds != null ? tempTaskInsetBounds : bounds);
+ task.updateOverrideConfiguration(taskBounds, insetBounds);
}
}
@@ -2069,14 +2069,16 @@
// static stacks need to be adjusted so they don't overlap with the docked stack.
// We get the bounds to use from window manager which has been adjusted for any
// screen controls and is also the same for all stacks.
- mWindowManager.getStackDockedModeBounds(
- HOME_STACK_ID, tempRect, true /* ignoreVisibility */);
+ if (dockedBounds != null) {
+ mWindowManager.getStackDockedModeBounds(
+ HOME_STACK_ID, tempRect, true /* ignoreVisibility */);
+ }
for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
if (StackId.isResizeableByDockedStack(i)) {
ActivityStack otherStack = getStack(i);
if (otherStack != null) {
- resizeStackLocked(i, tempRect, tempOtherTaskBounds,
- tempOtherTaskInsetBounds, preserveWindows,
+ resizeStackLocked(i, dockedBounds != null ? tempRect : null,
+ tempOtherTaskBounds, tempOtherTaskInsetBounds, preserveWindows,
true /* allowResizeInDockedMode */);
}
}
@@ -2738,12 +2740,21 @@
// Called when WindowManager has finished animating the launchingBehind activity to the back.
void handleLaunchTaskBehindCompleteLocked(ActivityRecord r) {
- r.mLaunchTaskBehind = false;
final TaskRecord task = r.task;
- task.setLastThumbnailLocked(task.stack.screenshotActivitiesLocked(r));
+ final ActivityStack stack = task.stack;
+
+ r.mLaunchTaskBehind = false;
+ task.setLastThumbnailLocked(stack.screenshotActivitiesLocked(r));
mRecentTasks.addLocked(task);
mService.notifyTaskStackChangedLocked();
mWindowManager.setAppVisibility(r.appToken, false);
+
+ // When launching tasks behind, update the last active time of the top task after the new
+ // task has been shown briefly
+ final ActivityRecord top = stack.topActivity();
+ if (top != null) {
+ top.task.touchActiveTime();
+ }
}
void scheduleLaunchTaskBehindComplete(IBinder token) {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index b157070..e32d1d1 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -285,6 +285,7 @@
mCallingPackage = info.packageName;
setIntent(_intent, info);
setMinDimensions(info);
+ touchActiveTime();
}
TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
@@ -315,6 +316,7 @@
taskType = APPLICATION_ACTIVITY_TYPE;
mTaskToReturnTo = HOME_ACTIVITY_TYPE;
lastTaskDescription = _taskDescription;
+ touchActiveTime();
}
private TaskRecord(ActivityManagerService service, int _taskId, Intent _intent,
diff --git a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
index 7cac227..f91db78 100644
--- a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
+++ b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
@@ -18,18 +18,21 @@
import com.android.server.SystemService;
+import android.app.PendingIntent;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.net.ConnectivityMetricsEvent;
import android.net.ConnectivityMetricsLogger;
import android.net.IConnectivityMetricsLogger;
-import android.net.IConnectivityMetricsLoggerSubscriber;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.ArrayMap;
+import android.os.Binder;
+import android.os.Parcel;
+import android.text.format.DateUtils;
import android.util.Log;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayDeque;
import java.util.ArrayList;
-import java.util.List;
/** {@hide} */
public class MetricsLoggerService extends SystemService {
@@ -43,134 +46,307 @@
@Override
public void onStart() {
+ resetThrottlingCounters(System.currentTimeMillis());
}
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
- Log.d(TAG, "onBootPhase: PHASE_SYSTEM_SERVICES_READY");
+ if (DBG) Log.d(TAG, "onBootPhase: PHASE_SYSTEM_SERVICES_READY");
publishBinderService(ConnectivityMetricsLogger.CONNECTIVITY_METRICS_LOGGER_SERVICE,
mBinder);
}
}
- private final int MAX_NUMBER_OF_EVENTS = 100;
- private final int MAX_TIME_OFFSET = 15*60*1000; // 15 minutes
- private final List<ConnectivityMetricsEvent> mEvents = new ArrayList<>();
- private long mLastSentEventTimeMillis = System.currentTimeMillis();
+ // TODO: read from system property
+ private final int MAX_NUMBER_OF_EVENTS = 1000;
- private final void enforceConnectivityInternalPermission() {
+ // TODO: read from system property
+ private final int EVENTS_NOTIFICATION_THRESHOLD = 300;
+
+ // TODO: read from system property
+ private final int THROTTLING_TIME_INTERVAL_MILLIS = 60 * 60 * 1000; // 1 hour
+
+ // TODO: read from system property
+ private final int THROTTLING_MAX_NUMBER_OF_MESSAGES_PER_COMPONENT = 1000;
+
+ private int mEventCounter = 0;
+
+ /**
+ * Reference of the last event in the list of cached events.
+ *
+ * When client of this service retrieves events by calling getEvents, it is passing
+ * ConnectivityMetricsEvent.Reference object. After getEvents returns, that object will
+ * contain this reference. The client can save it and use next time it calls getEvents.
+ * This way only new events will be returned.
+ */
+ private long mLastEventReference = 0;
+
+ private final int mThrottlingCounters[] =
+ new int[ConnectivityMetricsLogger.NUMBER_OF_COMPONENTS];
+
+ private long mThrottlingIntervalBoundaryMillis;
+
+ private final ArrayDeque<ConnectivityMetricsEvent> mEvents = new ArrayDeque<>();
+
+ private void enforceConnectivityInternalPermission() {
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.CONNECTIVITY_INTERNAL,
"MetricsLoggerService");
}
+ private void enforceDumpPermission() {
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.DUMP,
+ "MetricsLoggerService");
+ }
+
+ private void resetThrottlingCounters(long currentTimeMillis) {
+ for (int i = 0; i < mThrottlingCounters.length; i++) {
+ mThrottlingCounters[i] = 0;
+ }
+ mThrottlingIntervalBoundaryMillis =
+ currentTimeMillis + THROTTLING_TIME_INTERVAL_MILLIS;
+ }
+
+ private void addEvent(ConnectivityMetricsEvent e) {
+ if (VDBG) {
+ Log.v(TAG, "writeEvent(" + e.toString() + ")");
+ }
+
+ while (mEvents.size() >= MAX_NUMBER_OF_EVENTS) {
+ mEvents.removeFirst();
+ }
+
+ mEvents.addLast(e);
+ }
+
/**
* Implementation of the IConnectivityMetricsLogger interface.
*/
private final IConnectivityMetricsLogger.Stub mBinder = new IConnectivityMetricsLogger.Stub() {
- private final ArrayMap<IConnectivityMetricsLoggerSubscriber,
- IBinder.DeathRecipient> mSubscribers = new ArrayMap<>();
+ private final ArrayList<PendingIntent> mPendingIntents = new ArrayList<>();
-
- private ConnectivityMetricsEvent[] prepareEventsToSendIfReady() {
- ConnectivityMetricsEvent[] eventsToSend = null;
- final long currentTimeMillis = System.currentTimeMillis();
- final long timeOffset = currentTimeMillis - mLastSentEventTimeMillis;
- if (timeOffset >= MAX_TIME_OFFSET
- || timeOffset < 0 // system time has changed
- || mEvents.size() >= MAX_NUMBER_OF_EVENTS) {
- // batch events
- mLastSentEventTimeMillis = currentTimeMillis;
- eventsToSend = new ConnectivityMetricsEvent[mEvents.size()];
- mEvents.toArray(eventsToSend);
- mEvents.clear();
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump ConnectivityMetricsLoggerService " +
+ "from from pid=" + Binder.getCallingPid() + ", uid=" +
+ Binder.getCallingUid());
+ return;
}
- return eventsToSend;
- }
- private void maybeSendEventsToSubscribers(ConnectivityMetricsEvent[] eventsToSend) {
- if (eventsToSend == null || eventsToSend.length == 0) return;
- synchronized (mSubscribers) {
- for (IConnectivityMetricsLoggerSubscriber s : mSubscribers.keySet()) {
- try {
- s.onEvents(eventsToSend);
- } catch (RemoteException ex) {
- Log.e(TAG, "RemoteException " + ex);
- }
- }
- }
- }
+ boolean dumpSerializedSize = false;
+ boolean dumpEvents = false;
+ for (String arg : args) {
+ switch (arg) {
+ case "--events":
+ dumpEvents = true;
+ break;
- public void logEvent(ConnectivityMetricsEvent event) {
- ConnectivityMetricsEvent[] events = new ConnectivityMetricsEvent[]{event};
- logEvents(events);
- }
+ case "--size":
+ dumpSerializedSize = true;
+ break;
- public void logEvents(ConnectivityMetricsEvent[] events) {
- enforceConnectivityInternalPermission();
- ConnectivityMetricsEvent[] eventsToSend;
-
- if (VDBG) {
- for (ConnectivityMetricsEvent e : events) {
- Log.v(TAG, "writeEvent(" + e.toString() + ")");
+ case "--all":
+ dumpEvents = true;
+ dumpSerializedSize = true;
+ break;
}
}
synchronized (mEvents) {
- for (ConnectivityMetricsEvent e : events) {
- mEvents.add(e);
+ pw.println("Number of events: " + mEvents.size());
+ pw.println("Time span: " +
+ DateUtils.formatElapsedTime(
+ (System.currentTimeMillis() - mEvents.peekFirst().timestamp)
+ / 1000));
+
+ if (dumpSerializedSize) {
+ long dataSize = 0;
+ Parcel p = Parcel.obtain();
+ for (ConnectivityMetricsEvent e : mEvents) {
+ dataSize += 16; // timestamp and 2 stamps
+
+ p.writeParcelable(e.data, 0);
+ }
+ dataSize += p.dataSize();
+ p.recycle();
+ pw.println("Serialized data size: " + dataSize);
}
- eventsToSend = prepareEventsToSendIfReady();
+ if (dumpEvents) {
+ pw.println();
+ pw.println("Events:");
+ for (ConnectivityMetricsEvent e : mEvents) {
+ pw.println(e.toString());
+ }
+ }
}
- maybeSendEventsToSubscribers(eventsToSend);
+ if (!mPendingIntents.isEmpty()) {
+ pw.println();
+ pw.println("Pending intents:");
+ for (PendingIntent pi : mPendingIntents) {
+ pw.println(pi.toString());
+ }
+ }
}
- public boolean subscribe(IConnectivityMetricsLoggerSubscriber subscriber) {
- enforceConnectivityInternalPermission();
- if (VDBG) Log.v(TAG, "subscribe");
+ public long logEvent(ConnectivityMetricsEvent event) {
+ ConnectivityMetricsEvent[] events = new ConnectivityMetricsEvent[]{event};
+ return logEvents(events);
+ }
- synchronized (mSubscribers) {
- if (mSubscribers.containsKey(subscriber)) {
- Log.e(TAG, "subscriber is already subscribed");
- return false;
+ /**
+ * @param events
+ *
+ * Note: All events must belong to the same component.
+ *
+ * @return 0 on success
+ * <0 if error happened
+ * >0 timestamp after which new events will be accepted
+ */
+ public long logEvents(ConnectivityMetricsEvent[] events) {
+ enforceConnectivityInternalPermission();
+
+ if (events == null || events.length == 0) {
+ Log.wtf(TAG, "No events passed to logEvents()");
+ return -1;
+ }
+
+ int componentTag = events[0].componentTag;
+ if (componentTag < 0 ||
+ componentTag >= ConnectivityMetricsLogger.NUMBER_OF_COMPONENTS) {
+ Log.wtf(TAG, "Unexpected tag: " + componentTag);
+ return -1;
+ }
+
+ synchronized (mThrottlingCounters) {
+ long currentTimeMillis = System.currentTimeMillis();
+ if (currentTimeMillis > mThrottlingIntervalBoundaryMillis) {
+ resetThrottlingCounters(currentTimeMillis);
}
- final IConnectivityMetricsLoggerSubscriber s = subscriber;
- IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
- @Override
- public void binderDied() {
- if (VDBG) Log.v(TAG, "subscriber died");
- synchronized (mSubscribers) {
- mSubscribers.remove(s);
+
+ mThrottlingCounters[componentTag] += events.length;
+
+ if (mThrottlingCounters[componentTag] >
+ THROTTLING_MAX_NUMBER_OF_MESSAGES_PER_COMPONENT) {
+ Log.w(TAG, "Too many events from #" + componentTag +
+ ". Block until " + mThrottlingIntervalBoundaryMillis);
+
+ return mThrottlingIntervalBoundaryMillis;
+ }
+ }
+
+ boolean sendPendingIntents = false;
+
+ synchronized (mEvents) {
+ for (ConnectivityMetricsEvent e : events) {
+ if (e.componentTag != componentTag) {
+ Log.wtf(TAG, "Unexpected tag: " + e.componentTag);
+ return -1;
+ }
+
+ addEvent(e);
+ }
+
+ mLastEventReference += events.length;
+
+ mEventCounter += events.length;
+ if (mEventCounter >= EVENTS_NOTIFICATION_THRESHOLD) {
+ mEventCounter = 0;
+ sendPendingIntents = true;
+ }
+ }
+
+ if (sendPendingIntents) {
+ synchronized (mPendingIntents) {
+ for (PendingIntent pi : mPendingIntents) {
+ if (VDBG) Log.v(TAG, "Send pending intent");
+ try {
+ pi.send(getContext(), 0, null, null, null);
+ } catch (PendingIntent.CanceledException e) {
+ Log.e(TAG, "Pending intent canceled: " + pi);
+ mPendingIntents.remove(pi);
}
}
- };
-
- try {
- subscriber.asBinder().linkToDeath(dr, 0);
- mSubscribers.put(subscriber, dr);
- } catch (RemoteException e) {
- Log.e(TAG, "subscribe failed: " + e);
- return false;
}
}
+ return 0;
+ }
+
+ /**
+ * Retrieve events
+ *
+ * @param reference of the last event previously returned. The function will return
+ * events following it.
+ * If 0 then all events will be returned.
+ * After the function call it will contain reference of the
+ * last returned event.
+ * @return events
+ */
+ public ConnectivityMetricsEvent[] getEvents(ConnectivityMetricsEvent.Reference reference) {
+ enforceDumpPermission();
+ long ref = reference.value;
+ if (VDBG) Log.v(TAG, "getEvents(" + ref + ")");
+
+ ConnectivityMetricsEvent[] result;
+ synchronized (mEvents) {
+ if (ref > mLastEventReference) {
+ Log.e(TAG, "Invalid reference");
+ reference.value = mLastEventReference;
+ return null;
+ }
+ if (ref < mLastEventReference - mEvents.size()) {
+ ref = mLastEventReference - mEvents.size();
+ }
+
+ int numEventsToSkip =
+ mEvents.size() // Total number of events
+ - (int)(mLastEventReference - ref); // Number of events to return
+
+ result = new ConnectivityMetricsEvent[mEvents.size() - numEventsToSkip];
+ int i = 0;
+ for (ConnectivityMetricsEvent e : mEvents) {
+ if (numEventsToSkip > 0) {
+ numEventsToSkip--;
+ } else {
+ result[i++] = e;
+ }
+ }
+ }
+
+ reference.value = mLastEventReference;
+
+ return result;
+ }
+
+ public boolean register(PendingIntent newEventsIntent) {
+ enforceDumpPermission();
+ if (VDBG) Log.v(TAG, "register(" + newEventsIntent + ")");
+
+ synchronized (mPendingIntents) {
+ if (mPendingIntents.remove(newEventsIntent)) {
+ Log.w(TAG, "Replacing registered pending intent");
+ }
+ mPendingIntents.add(newEventsIntent);
+ }
+
return true;
}
- public void unsubscribe(IConnectivityMetricsLoggerSubscriber subscriber) {
- enforceConnectivityInternalPermission();
- if (VDBG) Log.v(TAG, "unsubscribe");
- synchronized (mSubscribers) {
- IBinder.DeathRecipient dr = mSubscribers.remove(subscriber);
- if (dr == null) {
- Log.e(TAG, "subscriber is not subscribed");
- return;
+ public void unregister(PendingIntent newEventsIntent) {
+ enforceDumpPermission();
+ if (VDBG) Log.v(TAG, "unregister(" + newEventsIntent + ")");
+
+ synchronized (mPendingIntents) {
+ if (!mPendingIntents.remove(newEventsIntent)) {
+ Log.e(TAG, "Pending intent is not registered");
}
- subscriber.asBinder().unlinkToDeath(dr, 0);
}
}
};
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index d10df02..2cba93fd 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -1211,6 +1211,11 @@
Log.e(TAG, "Error Tethering: " + e.toString());
setLastError(ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR);
+ try {
+ mNMService.untetherInterface(mIfaceName);
+ } catch (Exception ee) {
+ Log.e(TAG, "Error untethering after failure!" + ee.toString());
+ }
transitionTo(mInitialState);
return;
}
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 7f7ea9d..e9d9628 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -42,10 +42,10 @@
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
+import android.os.FactoryTest;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -59,6 +59,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
+import com.android.server.SystemService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -74,6 +75,29 @@
public final class ContentService extends IContentService.Stub {
private static final String TAG = "ContentService";
+ public static class Lifecycle extends SystemService {
+ private ContentService mContentService;
+
+ public Lifecycle(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ final boolean factoryTest = (FactoryTest
+ .getMode() == FactoryTest.FACTORY_TEST_LOW_LEVEL);
+ mContentService = new ContentService(getContext(), factoryTest);
+ publishBinderService(ContentResolver.CONTENT_SERVICE_NAME, mContentService);
+ }
+
+ @Override
+ public void onCleanupUser(int userHandle) {
+ synchronized (mContentService.mCache) {
+ mContentService.mCache.remove(userHandle);
+ }
+ }
+ }
+
private Context mContext;
private boolean mFactoryTest;
@@ -94,12 +118,18 @@
private BroadcastReceiver mCacheReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- final Uri data = intent.getData();
- if (data != null) {
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
- UserHandle.USER_NULL);
- final String packageName = data.getSchemeSpecificPart();
- invalidateCacheLocked(userId, packageName, null);
+ synchronized (mCache) {
+ if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
+ mCache.clear();
+ } else {
+ final Uri data = intent.getData();
+ if (data != null) {
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+ UserHandle.USER_NULL);
+ final String packageName = data.getSchemeSpecificPart();
+ invalidateCacheLocked(userId, packageName, null);
+ }
+ }
}
}
};
@@ -227,6 +257,11 @@
packageFilter.addDataScheme("package");
mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL,
packageFilter, null, null);
+
+ final IntentFilter localeFilter = new IntentFilter();
+ localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
+ mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL,
+ localeFilter, null, null);
}
public void systemReady() {
@@ -1080,12 +1115,6 @@
}
}
- public static ContentService main(Context context, boolean factoryTest) {
- ContentService service = new ContentService(context, factoryTest);
- ServiceManager.addService(ContentResolver.CONTENT_SERVICE_NAME, service);
- return service;
- }
-
/**
* Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS_FULL
* permission, if the userHandle is not for the caller.
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 1ed7070..8f8afd5 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -103,7 +103,6 @@
private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
// Brightness animation ramp rate in brightness units per second.
- private static final int BRIGHTNESS_RAMP_RATE_FAST = 200;
private static final int BRIGHTNESS_RAMP_RATE_SLOW = 40;
private static final int REPORTED_TO_POLICY_SCREEN_OFF = 0;
@@ -244,6 +243,9 @@
private boolean mAppliedDimming;
private boolean mAppliedLowPower;
+ // Brightness ramp rate fast.
+ private final int mBrightnessRampRateFast;
+
// The controller for the automatic brightness level.
private AutomaticBrightnessController mAutomaticBrightnessController;
@@ -303,6 +305,9 @@
mAllowAutoBrightnessWhileDozingConfig = resources.getBoolean(
com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing);
+ mBrightnessRampRateFast = resources.getInteger(
+ com.android.internal.R.integer.config_brightness_ramp_rate_fast);
+
int lightSensorRate = resources.getInteger(
com.android.internal.R.integer.config_autoBrightnessLightSensorRate);
long brighteningLightDebounce = resources.getInteger(
@@ -698,7 +703,7 @@
if (!mPendingScreenOff) {
if (state == Display.STATE_ON || state == Display.STATE_DOZE) {
animateScreenBrightness(brightness,
- slowChange ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
+ slowChange ? BRIGHTNESS_RAMP_RATE_SLOW : mBrightnessRampRateFast);
} else {
animateScreenBrightness(brightness, 0);
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index a36e671..69c012e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -165,15 +165,13 @@
@ServiceThreadOnly
protected void onStandby(boolean initiatedByCec, int standbyAction) {
assertRunOnServiceThread();
- if (!mService.isControlEnabled() || initiatedByCec) {
+ if (!mService.isControlEnabled() || initiatedByCec || !mAutoTvOff) {
return;
}
switch (standbyAction) {
case HdmiControlService.STANDBY_SCREEN_OFF:
- if (mAutoTvOff) {
- mService.sendCecCommand(
- HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_TV));
- }
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_TV));
break;
case HdmiControlService.STANDBY_SHUTDOWN:
// ACTION_SHUTDOWN is taken as a signal to power off all the devices.
diff --git a/services/core/java/com/android/server/hdmi/HdmiLogger.java b/services/core/java/com/android/server/hdmi/HdmiLogger.java
index 0b201710..537df81 100644
--- a/services/core/java/com/android/server/hdmi/HdmiLogger.java
+++ b/services/core/java/com/android/server/hdmi/HdmiLogger.java
@@ -21,6 +21,7 @@
import android.os.SystemClock;
import android.util.Pair;
import android.util.Slog;
+import android.util.Log;
import java.util.HashMap;
@@ -42,6 +43,7 @@
// Logging duration for same error message.
private static final long ERROR_LOG_DURATTION_MILLIS = 20 * 1000; // 20s
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);
private static final ThreadLocal<HdmiLogger> sLogger = new ThreadLocal<>();
@@ -83,10 +85,9 @@
}
private void debugInternal(String logMessage) {
- if (true || IS_USER_BUILD) {
- return;
+ if (DEBUG) {
+ Slog.d(TAG, logMessage);
}
- Slog.d(TAG, logMessage);
}
private static final String toLogString(String logMessage, Object[] objs) {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 2595864..612bae2 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1940,16 +1940,14 @@
public void addRestrictBackgroundWhitelistedUid(int uid) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
final boolean oldStatus;
+ final boolean needFirewallRules;
synchronized (mRulesLock) {
oldStatus = mRestrictBackgroundWhitelistUids.get(uid);
if (oldStatus) {
if (LOGD) Slog.d(TAG, "uid " + uid + " is already whitelisted");
return;
}
- if (!isUidValidForWhitelistRules(uid)) {
- if (LOGD) Slog.d(TAG, "no need to whitelist uid " + uid);
- return;
- }
+ needFirewallRules = isUidValidForWhitelistRules(uid);
Slog.i(TAG, "adding uid " + uid + " to restrict background whitelist");
mRestrictBackgroundWhitelistUids.append(uid, true);
if (mDefaultRestrictBackgroundWhitelistUids.get(uid)
@@ -1958,10 +1956,14 @@
+ " from revoked restrict background whitelist");
mRestrictBackgroundWhitelistRevokedUids.delete(uid);
}
- updateRuleForRestrictBackgroundLocked(uid);
+ if (needFirewallRules) {
+ // Only update firewall rules if necessary...
+ updateRuleForRestrictBackgroundLocked(uid);
+ }
+ // ...but always persists the whitelist request.
writePolicyLocked();
}
- if (mRestrictBackground && !oldStatus) {
+ if (mRestrictBackground && !oldStatus && needFirewallRules) {
mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0)
.sendToTarget();
}
@@ -1991,10 +1993,7 @@
if (LOGD) Slog.d(TAG, "uid " + uid + " was not whitelisted before");
return false;
}
- if (!uidDeleted && !isUidValidForWhitelistRules(uid)) {
- if (LOGD) Slog.d(TAG, "no need to remove whitelist for uid " + uid);
- return false;
- }
+ final boolean needFirewallRules = uidDeleted || isUidValidForWhitelistRules(uid);
Slog.i(TAG, "removing uid " + uid + " from restrict background whitelist");
mRestrictBackgroundWhitelistUids.delete(uid);
if (mDefaultRestrictBackgroundWhitelistUids.get(uid)
@@ -2003,13 +2002,17 @@
+ " to revoked restrict background whitelist");
mRestrictBackgroundWhitelistRevokedUids.append(uid, true);
}
- updateRuleForRestrictBackgroundLocked(uid, uidDeleted);
+ if (needFirewallRules) {
+ // Only update firewall rules if necessary...
+ updateRuleForRestrictBackgroundLocked(uid, uidDeleted);
+ }
if (updateNow) {
+ // ...but always persists the whitelist request.
writePolicyLocked();
}
// Status only changes if Data Saver is turned on (otherwise it is DISABLED, even if the
// app was whitelisted before).
- return mRestrictBackground;
+ return mRestrictBackground && needFirewallRules;
}
@Override
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
index 9cfb590..d339f69 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
@@ -24,7 +24,6 @@
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -35,7 +34,6 @@
import android.net.NetworkTemplate;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
-import android.os.Binder;
import android.os.RemoteException;
import android.os.ShellCommand;
import android.util.Log;
@@ -88,12 +86,10 @@
pw.println(" Adds a UID to the whitelist for restrict background usage.");
pw.println(" add restrict-background-blacklist UID");
pw.println(" Adds a UID to the blacklist for restrict background usage.");
- pw.println(" get metered-network ID");
- pw.println(" Checks whether the given non-mobile network is metered or not.");
pw.println(" get restrict-background");
pw.println(" Gets the global restrict background usage status.");
- pw.println(" list metered-networks [BOOLEAN]");
- pw.println(" Lists all non-mobile networks and whether they are metered or not.");
+ pw.println(" list wifi-networks [BOOLEAN]");
+ pw.println(" Lists all saved wifi networks and whether they are metered or not.");
pw.println(" If a boolean argument is passed, filters just the metered (or unmetered)");
pw.println(" networks.");
pw.println(" list restrict-background-whitelist");
@@ -105,7 +101,7 @@
pw.println(" remove restrict-background-blacklist UID");
pw.println(" Removes a UID from the blacklist for restrict background usage.");
pw.println(" set metered-network ID BOOLEAN");
- pw.println(" Toggles whether the given non-mobile network is metered.");
+ pw.println(" Toggles whether the given wi-fi network is metered.");
pw.println(" set restrict-background BOOLEAN");
pw.println(" Sets the global restrict background usage status.");
}
@@ -118,8 +114,6 @@
return -1;
}
switch(type) {
- case "metered-network":
- return getMeteredWifiNetwork();
case "restrict-background":
return getRestrictBackground();
}
@@ -152,8 +146,8 @@
return -1;
}
switch(type) {
- case "metered-networks":
- return listMeteredWifiNetworks();
+ case "wifi-networks":
+ return listWifiNetworks();
case "restrict-background-whitelist":
return listRestrictBackgroundWhitelist();
case "restrict-background-blacklist":
@@ -284,7 +278,7 @@
return 0;
}
- private int listMeteredWifiNetworks() throws RemoteException {
+ private int listWifiNetworks() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final String arg = getNextArg();
final Boolean filter = arg == null ? null : Boolean.valueOf(arg);
@@ -299,23 +293,6 @@
return 0;
}
- private int getMeteredWifiNetwork() throws RemoteException {
- final PrintWriter pw = getOutPrintWriter();
- final String id = getNextArg();
- if (id == null) {
- pw.println("Error: didn't specify ID");
- return -1;
- }
- final List<NetworkPolicy> policies = getWifiPolicies();
- for (NetworkPolicy policy: policies) {
- if (id.equals(getNetworkId(policy))) {
- pw.println(policy.metered);
- return 0;
- }
- }
- return 0;
- }
-
private int setMeteredWifiNetwork() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final String id = getNextArg();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 022b10f..660f790 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -120,6 +120,7 @@
import android.widget.Toast;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
@@ -226,7 +227,7 @@
private VrManagerInternal mVrManagerInternal;
final IBinder mForegroundToken = new Binder();
- private WorkerHandler mHandler;
+ private Handler mHandler;
private final HandlerThread mRankingThread = new HandlerThread("ranker",
Process.THREAD_PRIORITY_BACKGROUND);
@@ -572,33 +573,9 @@
public void clearEffects() {
synchronized (mNotificationList) {
if (DBG) Slog.d(TAG, "clearEffects");
-
- // sound
- mSoundNotificationKey = null;
-
- long identity = Binder.clearCallingIdentity();
- try {
- final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
- if (player != null) {
- player.stopAsync();
- }
- } catch (RemoteException e) {
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
-
- // vibrate
- mVibrateNotificationKey = null;
- identity = Binder.clearCallingIdentity();
- try {
- mVibrator.cancel();
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
-
- // light
- mLights.clear();
- updateLightsLocked();
+ clearSoundLocked();
+ clearVibrateLocked();
+ clearLightsLocked();
}
}
@@ -658,6 +635,36 @@
}
};
+ private void clearSoundLocked() {
+ mSoundNotificationKey = null;
+ long identity = Binder.clearCallingIdentity();
+ try {
+ final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
+ if (player != null) {
+ player.stopAsync();
+ }
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ private void clearVibrateLocked() {
+ mVibrateNotificationKey = null;
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mVibrator.cancel();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ private void clearLightsLocked() {
+ // light
+ mLights.clear();
+ updateLightsLocked();
+ }
+
private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -764,10 +771,9 @@
cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
REASON_USER_STOPPED, null);
}
- } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED)) {
- boolean inQuietMode = intent.getBooleanExtra(Intent.EXTRA_QUIET_MODE, false);
+ } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- if (inQuietMode && userHandle >= 0) {
+ if (userHandle >= 0) {
cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
REASON_PROFILE_TURNED_OFF, null);
}
@@ -863,6 +869,26 @@
super(context);
}
+ @VisibleForTesting
+ void setAudioManager(AudioManager audioMananger) {
+ mAudioManager = audioMananger;
+ }
+
+ @VisibleForTesting
+ void setVibrator(Vibrator vibrator) {
+ mVibrator = vibrator;
+ }
+
+ @VisibleForTesting
+ void setSystemReady(boolean systemReady) {
+ mSystemReady = systemReady;
+ }
+
+ @VisibleForTesting
+ void setHandler(Handler handler) {
+ mHandler = handler;
+ }
+
@Override
public void onStart() {
Resources resources = getContext().getResources();
@@ -981,7 +1007,7 @@
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_REMOVED);
filter.addAction(Intent.ACTION_USER_UNLOCKED);
- filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
getContext().registerReceiver(mIntentReceiver, filter);
IntentFilter pkgFilter = new IntentFilter();
@@ -2492,12 +2518,14 @@
return false;
}
- private void buzzBeepBlinkLocked(NotificationRecord record) {
+ @VisibleForTesting
+ void buzzBeepBlinkLocked(NotificationRecord record) {
boolean buzz = false;
boolean beep = false;
boolean blink = false;
final Notification notification = record.sbn.getNotification();
+ final String key = record.getKey();
// Should this notification make noise, vibe, or use the LED?
final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_DEFAULT;
@@ -2521,9 +2549,15 @@
if (disableEffects != null) {
ZenLog.traceDisableEffects(record, disableEffects);
}
+
+ // Remember if this notification already owns the notification channels.
+ boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
+ boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
+
+ // These are set inside the conditional if the notification is allowed to make noise.
+ boolean hasValidVibrate = false;
+ boolean hasValidSound = false;
if (disableEffects == null
- && (!(record.isUpdate
- && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
&& (record.getUserId() == UserHandle.USER_ALL ||
record.getUserId() == currentUser ||
mUserProfiles.isCurrentProfile(record.getUserId()))
@@ -2532,10 +2566,6 @@
&& mAudioManager != null) {
if (DBG) Slog.v(TAG, "Interrupting!");
- sendAccessibilityEvent(notification, record.sbn.getPackageName());
-
- // sound
-
// should we use the default notification sound? (indicated either by
// DEFAULT_SOUND or because notification.sound is pointing at
// Settings.System.NOTIFICATION_SOUND)
@@ -2545,8 +2575,6 @@
.equals(notification.sound);
Uri soundUri = null;
- boolean hasValidSound = false;
-
if (useDefaultSound) {
soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
@@ -2559,88 +2587,105 @@
hasValidSound = (soundUri != null);
}
- if (hasValidSound) {
- boolean looping =
- (notification.flags & Notification.FLAG_INSISTENT) != 0;
- AudioAttributes audioAttributes = audioAttributesForNotification(notification);
- mSoundNotificationKey = record.getKey();
- // do not play notifications if stream volume is 0 (typically because
- // ringer mode is silent) or if there is a user of exclusive audio focus
- if ((mAudioManager.getStreamVolume(
- AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
- && !mAudioManager.isAudioFocusExclusive()) {
- final long identity = Binder.clearCallingIdentity();
- try {
- final IRingtonePlayer player =
- mAudioManager.getRingtonePlayer();
- if (player != null) {
- if (DBG) Slog.v(TAG, "Playing sound " + soundUri
- + " with attributes " + audioAttributes);
- player.playAsync(soundUri, record.sbn.getUser(), looping,
- audioAttributes);
- beep = true;
- }
- } catch (RemoteException e) {
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- }
-
- // vibrate
// Does the notification want to specify its own vibration?
final boolean hasCustomVibrate = notification.vibrate != null;
// new in 4.2: if there was supposed to be a sound and we're in vibrate
// mode, and no other vibration is specified, we fall back to vibration
final boolean convertSoundToVibration =
- !hasCustomVibrate
- && hasValidSound
- && (mAudioManager.getRingerModeInternal()
- == AudioManager.RINGER_MODE_VIBRATE);
+ !hasCustomVibrate
+ && hasValidSound
+ && (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE);
// The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
final boolean useDefaultVibrate =
(notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
- if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate)
- && !(mAudioManager.getRingerModeInternal()
- == AudioManager.RINGER_MODE_SILENT)) {
- mVibrateNotificationKey = record.getKey();
+ hasValidVibrate = useDefaultVibrate || convertSoundToVibration ||
+ hasCustomVibrate;
- if (useDefaultVibrate || convertSoundToVibration) {
- // Escalate privileges so we can use the vibrator even if the
- // notifying app does not have the VIBRATE permission.
- long identity = Binder.clearCallingIdentity();
- try {
- mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
- useDefaultVibrate ? mDefaultVibrationPattern
- : mFallbackVibrationPattern,
- ((notification.flags & Notification.FLAG_INSISTENT) != 0)
- ? 0: -1, audioAttributesForNotification(notification));
- buzz = true;
- } finally {
- Binder.restoreCallingIdentity(identity);
+ // We can alert, and we're allowed to alert, but if the developer asked us to only do
+ // it once, and we already have, then don't.
+ if (!(record.isUpdate
+ && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)) {
+
+ sendAccessibilityEvent(notification, record.sbn.getPackageName());
+
+ if (hasValidSound) {
+ boolean looping =
+ (notification.flags & Notification.FLAG_INSISTENT) != 0;
+ AudioAttributes audioAttributes = audioAttributesForNotification(notification);
+ mSoundNotificationKey = key;
+ // do not play notifications if stream volume is 0 (typically because
+ // ringer mode is silent) or if there is a user of exclusive audio focus
+ if ((mAudioManager.getStreamVolume(
+ AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
+ && !mAudioManager.isAudioFocusExclusive()) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ final IRingtonePlayer player =
+ mAudioManager.getRingtonePlayer();
+ if (player != null) {
+ if (DBG) Slog.v(TAG, "Playing sound " + soundUri
+ + " with attributes " + audioAttributes);
+ player.playAsync(soundUri, record.sbn.getUser(), looping,
+ audioAttributes);
+ beep = true;
+ }
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
- } else if (notification.vibrate.length > 1) {
- // If you want your own vibration pattern, you need the VIBRATE
- // permission
- mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
- notification.vibrate,
- ((notification.flags & Notification.FLAG_INSISTENT) != 0)
- ? 0: -1, audioAttributesForNotification(notification));
- buzz = true;
+ }
+
+ if (hasValidVibrate && !(mAudioManager.getRingerModeInternal()
+ == AudioManager.RINGER_MODE_SILENT)) {
+ mVibrateNotificationKey = key;
+
+ if (useDefaultVibrate || convertSoundToVibration) {
+ // Escalate privileges so we can use the vibrator even if the
+ // notifying app does not have the VIBRATE permission.
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
+ useDefaultVibrate ? mDefaultVibrationPattern
+ : mFallbackVibrationPattern,
+ ((notification.flags & Notification.FLAG_INSISTENT) != 0)
+ ? 0: -1, audioAttributesForNotification(notification));
+ buzz = true;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ } else if (notification.vibrate.length > 1) {
+ // If you want your own vibration pattern, you need the VIBRATE
+ // permission
+ mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
+ notification.vibrate,
+ ((notification.flags & Notification.FLAG_INSISTENT) != 0)
+ ? 0: -1, audioAttributesForNotification(notification));
+ buzz = true;
+ }
}
}
+
+ }
+ // If a notification is updated to remove the actively playing sound or vibrate,
+ // cancel that feedback now
+ if (wasBeep && !hasValidSound) {
+ clearSoundLocked();
+ }
+ if (wasBuzz && !hasValidVibrate) {
+ clearVibrateLocked();
}
// light
// release the light
- boolean wasShowLights = mLights.remove(record.getKey());
+ boolean wasShowLights = mLights.remove(key);
if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold
&& ((record.getSuppressedVisualEffects()
& NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
- mLights.add(record.getKey());
+ mLights.add(key);
updateLightsLocked();
if (mUseAttentionLight) {
mAttentionLight.pulse();
@@ -2654,7 +2699,7 @@
& NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) {
if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
} else {
- EventLogTags.writeNotificationAlert(record.getKey(),
+ EventLogTags.writeNotificationAlert(key,
buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
mHandler.post(mBuzzBeepBlinked);
}
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 13a96ae..098b39e 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -247,10 +247,8 @@
}
// SetupWizard
- Intent setupIntent = new Intent(Intent.ACTION_MAIN);
- setupIntent.addCategory(Intent.CATEGORY_SETUP_WIZARD);
- PackageParser.Package setupPackage = getDefaultSystemHandlerActivityPackageLPr(
- setupIntent, userId);
+ PackageParser.Package setupPackage = getSystemPackageLPr(
+ mService.mSetupWizardPackage);
if (setupPackage != null
&& doesPackageSupportRuntimePermissions(setupPackage)) {
grantRuntimePermissionsLPw(setupPackage, PHONE_PERMISSIONS, userId);
@@ -597,6 +595,16 @@
grantRuntimePermissionsLPw(emergencyInfoPckg, PHONE_PERMISSIONS, true, userId);
}
+ // NFC Tag viewer
+ Intent nfcTagIntent = new Intent(Intent.ACTION_VIEW);
+ nfcTagIntent.setType("vnd.android.cursor.item/ndef_msg");
+ PackageParser.Package nfcTagPkg = getDefaultSystemHandlerActivityPackageLPr(
+ nfcTagIntent, userId);
+ if (nfcTagPkg != null
+ && doesPackageSupportRuntimePermissions(nfcTagPkg)) {
+ grantRuntimePermissionsLPw(nfcTagPkg, CONTACTS_PERMISSIONS, false, userId);
+ grantRuntimePermissionsLPw(nfcTagPkg, PHONE_PERMISSIONS, false, userId);
+ }
mService.mSettings.onDefaultRuntimePermissionsGrantedLPr(userId);
}
}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 7c71fbc..4c18e15 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -60,6 +60,7 @@
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -77,7 +78,6 @@
@Override
public void onStart() {
- Binder.LOG_RUNTIME_EXCEPTION = true;
publishBinderService(Context.LAUNCHER_APPS_SERVICE, mLauncherAppsImpl);
}
@@ -121,6 +121,21 @@
return getCallingUid();
}
+ final int injectCallingUserId() {
+ return UserHandle.getUserId(injectBinderCallingUid());
+ }
+
+ @VisibleForTesting
+ long injectClearCallingIdentity() {
+ return Binder.clearCallingIdentity();
+ }
+
+ // Injection point.
+ @VisibleForTesting
+ void injectRestoreCallingIdentity(long token) {
+ Binder.restoreCallingIdentity(token);
+ }
+
private int getCallingUserId() {
return UserHandle.getUserId(injectBinderCallingUid());
}
@@ -197,14 +212,13 @@
/**
* Checks if the caller is in the same group as the userToCheck.
*/
- @VisibleForTesting // We override it in unit tests
- void ensureInUserProfiles(UserHandle userToCheck, String message) {
- final int callingUserId = UserHandle.getCallingUserId();
+ private void ensureInUserProfiles(UserHandle userToCheck, String message) {
+ final int callingUserId = injectCallingUserId();
final int targetUserId = userToCheck.getIdentifier();
if (targetUserId == callingUserId) return;
- long ident = Binder.clearCallingIdentity();
+ long ident = injectClearCallingIdentity();
try {
UserInfo callingUserInfo = mUm.getUserInfo(callingUserId);
UserInfo targetUserInfo = mUm.getUserInfo(targetUserId);
@@ -214,7 +228,7 @@
throw new SecurityException(message);
}
} finally {
- Binder.restoreCallingIdentity(ident);
+ injectRestoreCallingIdentity(ident);
}
}
@@ -239,12 +253,12 @@
* Checks if the user is enabled.
*/
private boolean isUserEnabled(UserHandle user) {
- long ident = Binder.clearCallingIdentity();
+ long ident = injectClearCallingIdentity();
try {
UserInfo targetUserInfo = mUm.getUserInfo(user.getIdentifier());
return targetUserInfo != null && targetUserInfo.isEnabled();
} finally {
- Binder.restoreCallingIdentity(ident);
+ injectRestoreCallingIdentity(ident);
}
}
@@ -345,6 +359,9 @@
public ParceledListSlice getShortcuts(String callingPackage, long changedSince,
String packageName, ComponentName componentName, int flags, UserHandle user) {
ensureShortcutPermission(callingPackage, user);
+ if (!isUserEnabled(user)) {
+ return new ParceledListSlice<>(new ArrayList(0));
+ }
return new ParceledListSlice<>(
mShortcutServiceInternal.getShortcuts(getCallingUserId(),
@@ -356,6 +373,9 @@
public ParceledListSlice getShortcutInfo(String callingPackage, String packageName,
List<String> ids, UserHandle user) {
ensureShortcutPermission(callingPackage, user);
+ if (!isUserEnabled(user)) {
+ return new ParceledListSlice<>(new ArrayList(0));
+ }
return new ParceledListSlice<>(
mShortcutServiceInternal.getShortcutInfo(getCallingUserId(),
@@ -366,6 +386,10 @@
public void pinShortcuts(String callingPackage, String packageName, List<String> ids,
UserHandle user) {
ensureShortcutPermission(callingPackage, user);
+ if (!isUserEnabled(user)) {
+ throw new IllegalStateException("Cannot pin shortcuts for disabled profile "
+ + user);
+ }
mShortcutServiceInternal.pinShortcuts(getCallingUserId(),
callingPackage, packageName, ids, user.getIdentifier());
@@ -375,6 +399,9 @@
public int getShortcutIconResId(String callingPackage, ShortcutInfo shortcut,
UserHandle user) {
ensureShortcutPermission(callingPackage, user);
+ if (!isUserEnabled(user)) {
+ return 0;
+ }
return mShortcutServiceInternal.getShortcutIconResId(getCallingUserId(),
callingPackage, shortcut, user.getIdentifier());
@@ -384,6 +411,9 @@
public ParcelFileDescriptor getShortcutIconFd(String callingPackage, ShortcutInfo shortcut,
UserHandle user) {
ensureShortcutPermission(callingPackage, user);
+ if (!isUserEnabled(user)) {
+ return null;
+ }
return mShortcutServiceInternal.getShortcutIconFd(getCallingUserId(),
callingPackage, shortcut, user.getIdentifier());
@@ -402,6 +432,11 @@
verifyCallingPackage(callingPackage);
ensureInUserProfiles(user, "Cannot start activity for unrelated profile " + user);
+ if (!isUserEnabled(user)) {
+ throw new IllegalStateException("Cannot start a shortcut for disabled profile "
+ + user);
+ }
+
// Even without the permission, pinned shortcuts are always launchable.
if (!mShortcutServiceInternal.isPinnedByCaller(getCallingUserId(),
callingPackage, packageName, shortcutId, user.getIdentifier())) {
@@ -530,13 +565,13 @@
/** Checks if user is a profile of or same as listeningUser.
* and the user is enabled. */
- boolean isEnabledProfileOf(UserHandle user, UserHandle listeningUser,
+ private boolean isEnabledProfileOf(UserHandle user, UserHandle listeningUser,
String debugMsg) {
if (user.getIdentifier() == listeningUser.getIdentifier()) {
if (DEBUG) Log.d(TAG, "Delivering msg to same user " + debugMsg);
return true;
}
- long ident = Binder.clearCallingIdentity();
+ long ident = injectClearCallingIdentity();
try {
UserInfo userInfo = mUm.getUserInfo(user.getIdentifier());
UserInfo listeningUserInfo = mUm.getUserInfo(listeningUser.getIdentifier());
@@ -557,7 +592,7 @@
return true;
}
} finally {
- Binder.restoreCallingIdentity(ident);
+ injectRestoreCallingIdentity(ident);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 4ca615d..d13f472 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -42,7 +42,7 @@
import static com.android.server.pm.Installer.DEXOPT_SAFEMODE;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
-import static com.android.server.pm.PackageManagerServiceCompilerMapping.getFullCompilerFilter;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.getNonProfileGuidedCompilerFilter;
/**
* Helper class for running dexopt command on packages.
@@ -144,9 +144,10 @@
if (isUsedByOtherApps(path)) {
checkProfiles = false;
- // TODO: Should we only upgrade to the non-profile-guided version? That is,
- // given verify-profile, should we move to interpret-only?
- targetCompilerFilter = getFullCompilerFilter();
+ targetCompilerFilter = getNonProfileGuidedCompilerFilter(targetCompilerFilter);
+ if (DexFile.isProfileGuidedCompilerFilter(targetCompilerFilter)) {
+ throw new IllegalStateException(targetCompilerFilter);
+ }
isProfileGuidedFilter = false;
break;
@@ -181,6 +182,10 @@
return DEX_OPT_FAILED;
}
dexoptNeeded = adjustDexoptNeeded(dexoptNeeded);
+ if (PackageManagerService.DEBUG_DEXOPT) {
+ Log.i(TAG, "DexoptNeeded for " + path + "@" + targetCompilerFilter + " is " +
+ dexoptNeeded);
+ }
final String dexoptType;
String oatDir = null;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 58592ff..4ce730f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -64,6 +64,7 @@
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
+import static android.content.pm.PackageManager.MATCH_FACTORY_ONLY;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.MOVE_FAILED_DEVICE_ADMIN;
@@ -75,6 +76,7 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.PackageParser.PARSE_IS_PRIVILEGED;
import static android.content.pm.PackageParser.isApkFile;
+import static android.os.Process.FIRST_APPLICATION_UID;
import static android.os.Process.PACKAGE_INFO_GID;
import static android.os.Process.SYSTEM_UID;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
@@ -114,6 +116,7 @@
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.IntentFilter.AuthorityEntry;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
import android.content.ServiceConnection;
@@ -146,6 +149,7 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.ActivityIntentInfo;
+import android.content.pm.PackageParser.IntentInfo;
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.PackageStats;
@@ -319,6 +323,7 @@
private static final boolean DEBUG_INTENT_MATCHING = false;
private static final boolean DEBUG_PACKAGE_SCANNING = false;
private static final boolean DEBUG_VERIFY = false;
+ private static final boolean DEBUG_FILTERS = false;
// Debug output for dexopting. This is shared between PackageManagerService, OtaDexoptService
// and PackageDexOptimizer. All these classes have their own flag to allow switching a single
@@ -444,6 +449,18 @@
sBrowserIntent.setData(Uri.parse("http:"));
}
+ /**
+ * The set of all protected actions [i.e. those actions for which a high priority
+ * intent filter is disallowed].
+ */
+ private static final Set<String> PROTECTED_ACTIONS = new ArraySet<>();
+ static {
+ PROTECTED_ACTIONS.add(Intent.ACTION_SEND);
+ PROTECTED_ACTIONS.add(Intent.ACTION_SENDTO);
+ PROTECTED_ACTIONS.add(Intent.ACTION_SEND_MULTIPLE);
+ PROTECTED_ACTIONS.add(Intent.ACTION_VIEW);
+ }
+
// Compilation reasons.
public static final int REASON_FIRST_BOOT = 0;
public static final int REASON_BOOT = 1;
@@ -530,6 +547,20 @@
* are package location.
*/
final private ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();
+ /**
+ * Tracks high priority intent filters for protected actions. During boot, certain
+ * filter actions are protected and should never be allowed to have a high priority
+ * intent filter for them. However, there is one, and only one exception -- the
+ * setup wizard. It must be able to define a high priority intent filter for these
+ * actions to ensure there are no escapes from the wizard. We need to delay processing
+ * of these during boot as we need to look at all of the system packages in order
+ * to know which component is the setup wizard.
+ */
+ private final List<PackageParser.ActivityIntentInfo> mProtectedFilters = new ArrayList<>();
+ /**
+ * Whether or not processing protected filters should be deferred.
+ */
+ private boolean mDeferProtectedFilters = true;
/**
* Tracks existing system packages prior to receiving an OTA. Keys are package name.
@@ -1034,6 +1065,7 @@
final @Nullable String mRequiredVerifierPackage;
final @Nullable String mRequiredInstallerPackage;
+ final @Nullable String mSetupWizardPackage;
private final PackageUsage mPackageUsage = new PackageUsage();
@@ -2427,6 +2459,36 @@
}
mExpectingBetter.clear();
+ // Resolve protected action filters. Only the setup wizard is allowed to
+ // have a high priority filter for these actions.
+ mSetupWizardPackage = getSetupWizardPackageName();
+ if (mProtectedFilters.size() > 0) {
+ if (DEBUG_FILTERS && mSetupWizardPackage == null) {
+ Slog.i(TAG, "No setup wizard;"
+ + " All protected intents capped to priority 0");
+ }
+ for (ActivityIntentInfo filter : mProtectedFilters) {
+ if (filter.activity.info.packageName.equals(mSetupWizardPackage)) {
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Found setup wizard;"
+ + " allow priority " + filter.getPriority() + ";"
+ + " package: " + filter.activity.info.packageName
+ + " activity: " + filter.activity.className
+ + " priority: " + filter.getPriority());
+ }
+ // skip setup wizard; allow it to keep the high priority filter
+ continue;
+ }
+ Slog.w(TAG, "Protected action; cap priority to 0;"
+ + " package: " + filter.activity.info.packageName
+ + " activity: " + filter.activity.className
+ + " origPrio: " + filter.getPriority());
+ filter.setPriority(0);
+ }
+ }
+ mDeferProtectedFilters = false;
+ mProtectedFilters.clear();
+
// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
updateAllSharedLibrariesLPw();
@@ -2886,12 +2948,15 @@
return cur;
}
- PackageInfo generatePackageInfo(PackageParser.Package p, int flags, int userId) {
+ private PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
- final PackageSetting ps = (PackageSetting) p.mExtras;
if (ps == null) {
return null;
}
+ final PackageParser.Package p = ps.pkg;
+ if (p == null) {
+ return null;
+ }
final PermissionsState permissionsState = ps.getPermissionsState();
@@ -2961,14 +3026,28 @@
false /* requireFullPermission */, false /* checkShell */, "get package info");
// reader
synchronized (mPackages) {
- PackageParser.Package p = mPackages.get(packageName);
+ final boolean matchFactoryOnly = (flags & MATCH_FACTORY_ONLY) != 0;
+ PackageParser.Package p = null;
+ if (matchFactoryOnly) {
+ final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
+ if (ps != null) {
+ return generatePackageInfo(ps, flags, userId);
+ }
+ }
+ if (p == null) {
+ p = mPackages.get(packageName);
+ if (matchFactoryOnly && !isSystemApp(p)) {
+ return null;
+ }
+ }
if (DEBUG_PACKAGE_INFO)
Log.v(TAG, "getPackageInfo " + packageName + ": " + p);
if (p != null) {
- return generatePackageInfo(p, flags, userId);
+ return generatePackageInfo((PackageSetting)p.mExtras, flags, userId);
}
- if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
- return generatePackageInfoFromSettingsLPw(packageName, flags, userId);
+ if (!matchFactoryOnly && (flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ return generatePackageInfo(ps, flags, userId);
}
}
return null;
@@ -3129,8 +3208,7 @@
PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps != null) {
if (ps.pkg == null) {
- PackageInfo pInfo = generatePackageInfoFromSettingsLPw(packageName,
- flags, userId);
+ final PackageInfo pInfo = generatePackageInfo(ps, flags, userId);
if (pInfo != null) {
return pInfo.applicationInfo;
}
@@ -3142,31 +3220,6 @@
return null;
}
- private PackageInfo generatePackageInfoFromSettingsLPw(String packageName, int flags,
- int userId) {
- if (!sUserManager.exists(userId)) return null;
- PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps != null) {
- PackageParser.Package pkg = ps.pkg;
- if (pkg == null) {
- if ((flags & MATCH_UNINSTALLED_PACKAGES) == 0) {
- return null;
- }
- // Only data remains, so we aren't worried about code paths
- pkg = new PackageParser.Package(packageName);
- pkg.applicationInfo.packageName = packageName;
- pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY;
- pkg.applicationInfo.privateFlags = ps.pkgPrivateFlags;
- pkg.applicationInfo.uid = ps.appId;
- pkg.applicationInfo.initForUser(userId);
- pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;
- pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString;
- }
- return generatePackageInfo(pkg, flags, userId);
- }
- return null;
- }
-
@Override
public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
@@ -5915,11 +5968,11 @@
if (listUninstalled) {
list = new ArrayList<PackageInfo>(mSettings.mPackages.size());
for (PackageSetting ps : mSettings.mPackages.values()) {
- PackageInfo pi;
+ final PackageInfo pi;
if (ps.pkg != null) {
- pi = generatePackageInfo(ps.pkg, flags, userId);
+ pi = generatePackageInfo(ps, flags, userId);
} else {
- pi = generatePackageInfoFromSettingsLPw(ps.name, flags, userId);
+ pi = generatePackageInfo(ps, flags, userId);
}
if (pi != null) {
list.add(pi);
@@ -5928,7 +5981,8 @@
} else {
list = new ArrayList<PackageInfo>(mPackages.size());
for (PackageParser.Package p : mPackages.values()) {
- PackageInfo pi = generatePackageInfo(p, flags, userId);
+ final PackageInfo pi =
+ generatePackageInfo((PackageSetting)p.mExtras, flags, userId);
if (pi != null) {
list.add(pi);
}
@@ -5955,11 +6009,11 @@
if (numMatch == 0) {
return;
}
- PackageInfo pi;
+ final PackageInfo pi;
if (ps.pkg != null) {
- pi = generatePackageInfo(ps.pkg, flags, userId);
+ pi = generatePackageInfo(ps, flags, userId);
} else {
- pi = generatePackageInfoFromSettingsLPw(ps.name, flags, userId);
+ pi = generatePackageInfo(ps, flags, userId);
}
// The above might return null in cases of uninstalled apps or install-state
// skew across users/profiles.
@@ -9704,6 +9758,12 @@
// is granted only if it was already granted.
allowed = origPermissions.hasInstallPermission(perm);
}
+ if (!allowed && (bp.protectionLevel & PermissionInfo.PROTECTION_FLAG_SETUP) != 0
+ && pkg.packageName.equals(mSetupWizardPackage)) {
+ // If this permission is to be granted to the system setup wizard and
+ // this app is a setup wizard, then it gets the permission.
+ allowed = true;
+ }
}
return allowed;
}
@@ -9761,8 +9821,314 @@
return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
}
+ /**
+ * Finds a privileged activity that matches the specified activity names.
+ */
+ private PackageParser.Activity findMatchingActivity(
+ List<PackageParser.Activity> activityList, ActivityInfo activityInfo) {
+ for (PackageParser.Activity sysActivity : activityList) {
+ if (sysActivity.info.name.equals(activityInfo.name)) {
+ return sysActivity;
+ }
+ if (sysActivity.info.name.equals(activityInfo.targetActivity)) {
+ return sysActivity;
+ }
+ if (sysActivity.info.targetActivity != null) {
+ if (sysActivity.info.targetActivity.equals(activityInfo.name)) {
+ return sysActivity;
+ }
+ if (sysActivity.info.targetActivity.equals(activityInfo.targetActivity)) {
+ return sysActivity;
+ }
+ }
+ }
+ return null;
+ }
+
+ public class IterGenerator<E> {
+ public Iterator<E> generate(ActivityIntentInfo info) {
+ return null;
+ }
+ }
+
+ public class ActionIterGenerator extends IterGenerator<String> {
+ @Override
+ public Iterator<String> generate(ActivityIntentInfo info) {
+ return info.actionsIterator();
+ }
+ }
+
+ public class CategoriesIterGenerator extends IterGenerator<String> {
+ @Override
+ public Iterator<String> generate(ActivityIntentInfo info) {
+ return info.categoriesIterator();
+ }
+ }
+
+ public class SchemesIterGenerator extends IterGenerator<String> {
+ @Override
+ public Iterator<String> generate(ActivityIntentInfo info) {
+ return info.schemesIterator();
+ }
+ }
+
+ public class AuthoritiesIterGenerator extends IterGenerator<IntentFilter.AuthorityEntry> {
+ @Override
+ public Iterator<IntentFilter.AuthorityEntry> generate(ActivityIntentInfo info) {
+ return info.authoritiesIterator();
+ }
+ }
+
+ /**
+ * <em>WARNING</em> for performance reasons, the passed in intentList WILL BE
+ * MODIFIED. Do not pass in a list that should not be changed.
+ */
+ private <T> void getIntentListSubset(List<ActivityIntentInfo> intentList,
+ IterGenerator<T> generator, Iterator<T> searchIterator) {
+ // loop through the set of actions; every one must be found in the intent filter
+ while (searchIterator.hasNext()) {
+ // we must have at least one filter in the list to consider a match
+ if (intentList.size() == 0) {
+ break;
+ }
+
+ final T searchAction = searchIterator.next();
+
+ // loop through the set of intent filters
+ final Iterator<ActivityIntentInfo> intentIter = intentList.iterator();
+ while (intentIter.hasNext()) {
+ final ActivityIntentInfo intentInfo = intentIter.next();
+ boolean selectionFound = false;
+
+ // loop through the intent filter's selection criteria; at least one
+ // of them must match the searched criteria
+ final Iterator<T> intentSelectionIter = generator.generate(intentInfo);
+ while (intentSelectionIter != null && intentSelectionIter.hasNext()) {
+ final T intentSelection = intentSelectionIter.next();
+ if (intentSelection != null && intentSelection.equals(searchAction)) {
+ selectionFound = true;
+ break;
+ }
+ }
+
+ // the selection criteria wasn't found in this filter's set; this filter
+ // is not a potential match
+ if (!selectionFound) {
+ intentIter.remove();
+ }
+ }
+ }
+ }
+
+ private boolean isProtectedAction(ActivityIntentInfo filter) {
+ final Iterator<String> actionsIter = filter.actionsIterator();
+ while (actionsIter != null && actionsIter.hasNext()) {
+ final String filterAction = actionsIter.next();
+ if (PROTECTED_ACTIONS.contains(filterAction)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Adjusts the priority of the given intent filter according to policy.
+ * <p>
+ * <ul>
+ * <li>The priority for non privileged applications is capped to '0'</li>
+ * <li>The priority for protected actions on privileged applications is capped to '0'</li>
+ * <li>The priority for unbundled updates to privileged applications is capped to the
+ * priority defined on the system partition</li>
+ * </ul>
+ * <p>
+ * <em>NOTE:</em> There is one exception. For security reasons, the setup wizard is
+ * allowed to obtain any priority on any action.
+ */
+ private void adjustPriority(
+ List<PackageParser.Activity> systemActivities, ActivityIntentInfo intent) {
+ // nothing to do; priority is fine as-is
+ if (intent.getPriority() <= 0) {
+ return;
+ }
+
+ final ActivityInfo activityInfo = intent.activity.info;
+ final ApplicationInfo applicationInfo = activityInfo.applicationInfo;
+
+ final boolean privilegedApp =
+ ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0);
+ if (!privilegedApp) {
+ // non-privileged applications can never define a priority >0
+ Slog.w(TAG, "Non-privileged app; cap priority to 0;"
+ + " package: " + applicationInfo.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ intent.setPriority(0);
+ return;
+ }
+
+ if (systemActivities == null) {
+ // the system package is not disabled; we're parsing the system partition
+ if (isProtectedAction(intent)) {
+ if (mDeferProtectedFilters) {
+ // We can't deal with these just yet. No component should ever obtain a
+ // >0 priority for a protected actions, with ONE exception -- the setup
+ // wizard. The setup wizard, however, cannot be known until we're able to
+ // query it for the category CATEGORY_SETUP_WIZARD. Which we can't do
+ // until all intent filters have been processed. Chicken, meet egg.
+ // Let the filter temporarily have a high priority and rectify the
+ // priorities after all system packages have been scanned.
+ mProtectedFilters.add(intent);
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Protected action; save for later;"
+ + " package: " + applicationInfo.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ }
+ return;
+ } else {
+ if (DEBUG_FILTERS && mSetupWizardPackage == null) {
+ Slog.i(TAG, "No setup wizard;"
+ + " All protected intents capped to priority 0");
+ }
+ if (intent.activity.info.packageName.equals(mSetupWizardPackage)) {
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Found setup wizard;"
+ + " allow priority " + intent.getPriority() + ";"
+ + " package: " + intent.activity.info.packageName
+ + " activity: " + intent.activity.className
+ + " priority: " + intent.getPriority());
+ }
+ // setup wizard gets whatever it wants
+ return;
+ }
+ Slog.w(TAG, "Protected action; cap priority to 0;"
+ + " package: " + intent.activity.info.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ intent.setPriority(0);
+ return;
+ }
+ }
+ // privileged apps on the system image get whatever priority they request
+ return;
+ }
+
+ // privileged app unbundled update ... try to find the same activity
+ final PackageParser.Activity foundActivity =
+ findMatchingActivity(systemActivities, activityInfo);
+ if (foundActivity == null) {
+ // this is a new activity; it cannot obtain >0 priority
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "New activity; cap priority to 0;"
+ + " package: " + applicationInfo.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ }
+ intent.setPriority(0);
+ return;
+ }
+
+ // found activity, now check for filter equivalence
+
+ // a shallow copy is enough; we modify the list, not its contents
+ final List<ActivityIntentInfo> intentListCopy =
+ new ArrayList<>(foundActivity.intents);
+ final List<ActivityIntentInfo> foundFilters = findFilters(intent);
+
+ // find matching action subsets
+ final Iterator<String> actionsIterator = intent.actionsIterator();
+ if (actionsIterator != null) {
+ getIntentListSubset(
+ intentListCopy, new ActionIterGenerator(), actionsIterator);
+ if (intentListCopy.size() == 0) {
+ // no more intents to match; we're not equivalent
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Mismatched action; cap priority to 0;"
+ + " package: " + applicationInfo.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ }
+ intent.setPriority(0);
+ return;
+ }
+ }
+
+ // find matching category subsets
+ final Iterator<String> categoriesIterator = intent.categoriesIterator();
+ if (categoriesIterator != null) {
+ getIntentListSubset(intentListCopy, new CategoriesIterGenerator(),
+ categoriesIterator);
+ if (intentListCopy.size() == 0) {
+ // no more intents to match; we're not equivalent
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Mismatched category; cap priority to 0;"
+ + " package: " + applicationInfo.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ }
+ intent.setPriority(0);
+ return;
+ }
+ }
+
+ // find matching schemes subsets
+ final Iterator<String> schemesIterator = intent.schemesIterator();
+ if (schemesIterator != null) {
+ getIntentListSubset(intentListCopy, new SchemesIterGenerator(),
+ schemesIterator);
+ if (intentListCopy.size() == 0) {
+ // no more intents to match; we're not equivalent
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Mismatched scheme; cap priority to 0;"
+ + " package: " + applicationInfo.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ }
+ intent.setPriority(0);
+ return;
+ }
+ }
+
+ // find matching authorities subsets
+ final Iterator<IntentFilter.AuthorityEntry>
+ authoritiesIterator = intent.authoritiesIterator();
+ if (authoritiesIterator != null) {
+ getIntentListSubset(intentListCopy,
+ new AuthoritiesIterGenerator(),
+ authoritiesIterator);
+ if (intentListCopy.size() == 0) {
+ // no more intents to match; we're not equivalent
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Mismatched authority; cap priority to 0;"
+ + " package: " + applicationInfo.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ }
+ intent.setPriority(0);
+ return;
+ }
+ }
+
+ // we found matching filter(s); app gets the max priority of all intents
+ int cappedPriority = 0;
+ for (int i = intentListCopy.size() - 1; i >= 0; --i) {
+ cappedPriority = Math.max(cappedPriority, intentListCopy.get(i).getPriority());
+ }
+ if (intent.getPriority() > cappedPriority) {
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Found matching filter(s);"
+ + " cap priority to " + cappedPriority + ";"
+ + " package: " + applicationInfo.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ }
+ intent.setPriority(cappedPriority);
+ return;
+ }
+ // all this for nothing; the requested priority was <= what was on the system
+ }
+
public final void addActivity(PackageParser.Activity a, String type) {
- final boolean systemApp = a.info.applicationInfo.isSystemApp();
mActivities.put(a.getComponentName(), a);
if (DEBUG_SHOW_INFO)
Log.v(
@@ -9773,10 +10139,12 @@
final int NI = a.intents.size();
for (int j=0; j<NI; j++) {
PackageParser.ActivityIntentInfo intent = a.intents.get(j);
- if (!systemApp && intent.getPriority() > 0 && "activity".equals(type)) {
- intent.setPriority(0);
- Log.w(TAG, "Package " + a.info.applicationInfo.packageName + " has activity "
- + a.className + " with priority > 0, forcing to 0");
+ if ("activity".equals(type)) {
+ final PackageSetting ps =
+ mSettings.getDisabledSystemPkgLPr(intent.activity.info.packageName);
+ final List<PackageParser.Activity> systemActivities =
+ ps != null && ps.pkg != null ? ps.pkg.activities : null;
+ adjustPriority(systemActivities, intent);
}
if (DEBUG_SHOW_INFO) {
Log.v(TAG, " IntentFilter:");
@@ -9926,18 +10294,6 @@
out.println();
}
-// List<ResolveInfo> filterEnabled(List<ResolveInfo> resolveInfoList) {
-// final Iterator<ResolveInfo> i = resolveInfoList.iterator();
-// final List<ResolveInfo> retList = Lists.newArrayList();
-// while (i.hasNext()) {
-// final ResolveInfo resolveInfo = i.next();
-// if (isEnabledLP(resolveInfo.activityInfo)) {
-// retList.add(resolveInfo);
-// }
-// }
-// return retList;
-// }
-
// Keys are String (activity class name), values are Activity.
private final ArrayMap<ComponentName, PackageParser.Activity> mActivities
= new ArrayMap<ComponentName, PackageParser.Activity>();
@@ -11289,8 +11645,8 @@
* @return the current "allow unknown sources" setting
*/
private int getUnknownSourcesSettings() {
- return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
- android.provider.Settings.Global.INSTALL_NON_MARKET_APPS,
+ return android.provider.Settings.Secure.getInt(mContext.getContentResolver(),
+ android.provider.Settings.Secure.INSTALL_NON_MARKET_APPS,
-1);
}
@@ -12254,8 +12610,6 @@
* Called after the source arguments are copied. This is used mostly for
* MoveParams when it needs to read the source file to put it in the
* destination.
- *
- * @return
*/
int doPostCopy(int uid) {
return PackageManager.INSTALL_SUCCEEDED;
@@ -15501,17 +15855,14 @@
// Otherwise, reset the permission.
final int revokeResult = permissionsState.revokeRuntimePermission(bp, userId);
switch (revokeResult) {
- case PERMISSION_OPERATION_SUCCESS: {
- writeRuntimePermissions = true;
- } break;
-
+ case PERMISSION_OPERATION_SUCCESS:
case PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
writeRuntimePermissions = true;
final int appId = ps.appId;
mHandler.post(new Runnable() {
@Override
public void run() {
- killUid(appId, userId, KILL_APP_REASON_GIDS_CHANGED);
+ killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);
}
});
} break;
@@ -16626,6 +16977,21 @@
set, comp, userId);
}
+ private @Nullable String getSetupWizardPackageName() {
+ final Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(Intent.CATEGORY_SETUP_WIZARD);
+
+ final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, null,
+ MATCH_SYSTEM_ONLY | MATCH_DISABLED_COMPONENTS, UserHandle.myUserId());
+ if (matches.size() == 1) {
+ return matches.get(0).getComponentInfo().packageName;
+ } else {
+ Slog.e(TAG, "There should probably be exactly one setup wizard; found " + matches.size()
+ + ": matches=" + matches);
+ return null;
+ }
+ }
+
@Override
public void setApplicationEnabledSetting(String appPackageName,
int newState, int flags, int userId, String callingPackage) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index f1b7991..a7512db 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -126,4 +126,10 @@
return value;
}
+ /**
+ * Return the non-profile-guided filter corresponding to the given filter.
+ */
+ public static String getNonProfileGuidedCompilerFilter(String filter) {
+ return DexFile.getNonProfileGuidedCompilerFilter(filter);
+ }
}
diff --git a/services/core/java/com/android/server/pm/ShortcutBackupAgent.java b/services/core/java/com/android/server/pm/ShortcutBackupAgent.java
deleted file mode 100644
index a0fbc37..0000000
--- a/services/core/java/com/android/server/pm/ShortcutBackupAgent.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2016 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.pm;
-
-import android.app.backup.BlobBackupHelper;
-
-public class ShortcutBackupAgent extends BlobBackupHelper {
- private static final String TAG = "ShortcutBackupAgent";
- private static final int BLOB_VERSION = 1;
-
- public ShortcutBackupAgent(int currentBlobVersion, String... keys) {
- super(currentBlobVersion, keys);
- }
-
- @Override
- protected byte[] getBackupPayload(String key) {
- throw new RuntimeException("not implemented yet"); // todo
- }
-
- @Override
- protected void applyRestoredPayload(String key, byte[] payload) {
- throw new RuntimeException("not implemented yet"); // todo
- }
-}
diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java
index 7699f30..c6d66fe 100644
--- a/services/core/java/com/android/server/pm/ShortcutLauncher.java
+++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java
@@ -20,6 +20,10 @@
import android.content.pm.ShortcutInfo;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.ShortcutUser.PackageWithUser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -27,6 +31,7 @@
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -43,15 +48,16 @@
private static final String ATTR_LAUNCHER_USER_ID = "launcher-user";
private static final String ATTR_VALUE = "value";
private static final String ATTR_PACKAGE_NAME = "package-name";
+ private static final String ATTR_PACKAGE_USER_ID = "package-user";
private final int mOwnerUserId;
/**
* Package name -> IDs.
*/
- final private ArrayMap<String, ArraySet<String>> mPinnedShortcuts = new ArrayMap<>();
+ final private ArrayMap<PackageWithUser, ArraySet<String>> mPinnedShortcuts = new ArrayMap<>();
- public ShortcutLauncher(@UserIdInt int ownerUserId, @NonNull String packageName,
+ private ShortcutLauncher(@UserIdInt int ownerUserId, @NonNull String packageName,
@UserIdInt int launcherUserId, ShortcutPackageInfo spi) {
super(launcherUserId, packageName, spi != null ? spi : ShortcutPackageInfo.newEmpty());
mOwnerUserId = ownerUserId;
@@ -59,7 +65,7 @@
public ShortcutLauncher(@UserIdInt int ownerUserId, @NonNull String packageName,
@UserIdInt int launcherUserId) {
- this(launcherUserId, packageName, launcherUserId, null);
+ this(ownerUserId, packageName, launcherUserId, null);
}
@Override
@@ -67,16 +73,38 @@
return mOwnerUserId;
}
+ /**
+ * Called when the new package can't receive the backup, due to signature or version mismatch.
+ */
+ @Override
+ protected void onRestoreBlocked(ShortcutService s) {
+ final ArrayList<PackageWithUser> pinnedPackages =
+ new ArrayList<>(mPinnedShortcuts.keySet());
+ mPinnedShortcuts.clear();
+ for (int i = pinnedPackages.size() - 1; i >= 0; i--) {
+ final PackageWithUser pu = pinnedPackages.get(i);
+ s.getPackageShortcutsLocked(pu.packageName, pu.userId)
+ .refreshPinnedFlags(s);
+ }
+ }
+
+ @Override
+ protected void onRestored(ShortcutService s) {
+ // Nothing to do.
+ }
+
public void pinShortcuts(@NonNull ShortcutService s, @UserIdInt int packageUserId,
@NonNull String packageName, @NonNull List<String> ids) {
final ShortcutPackage packageShortcuts =
s.getPackageShortcutsLocked(packageName, packageUserId);
+ final PackageWithUser pu = PackageWithUser.of(packageUserId, packageName);
+
final int idSize = ids.size();
if (idSize == 0) {
- mPinnedShortcuts.remove(packageName);
+ mPinnedShortcuts.remove(pu);
} else {
- final ArraySet<String> prevSet = mPinnedShortcuts.get(packageName);
+ final ArraySet<String> prevSet = mPinnedShortcuts.get(pu);
// Pin shortcuts. Make sure only pin the ones that were visible to the caller.
// i.e. a non-dynamic, pinned shortcut by *other launchers* shouldn't be pinned here.
@@ -93,7 +121,7 @@
newSet.add(id);
}
}
- mPinnedShortcuts.put(packageName, newSet);
+ mPinnedShortcuts.put(pu, newSet);
}
packageShortcuts.refreshPinnedFlags(s);
}
@@ -101,12 +129,13 @@
/**
* Return the pinned shortcut IDs for the publisher package.
*/
- public ArraySet<String> getPinnedShortcutIds(@NonNull String packageName) {
- return mPinnedShortcuts.get(packageName);
+ public ArraySet<String> getPinnedShortcutIds(@NonNull String packageName,
+ @UserIdInt int packageUserId) {
+ return mPinnedShortcuts.get(PackageWithUser.of(packageUserId, packageName));
}
- boolean cleanUpPackage(String packageName) {
- return mPinnedShortcuts.remove(packageName) != null;
+ boolean cleanUpPackage(String packageName, @UserIdInt int packageUserId) {
+ return mPinnedShortcuts.remove(PackageWithUser.of(packageUserId, packageName)) != null;
}
/**
@@ -126,9 +155,15 @@
getPackageInfo().saveToXml(out);
for (int i = 0; i < size; i++) {
+ final PackageWithUser pu = mPinnedShortcuts.keyAt(i);
+
+ if (forBackup && (pu.userId != getOwnerUserId())) {
+ continue; // Target package on a different user, skip. (i.e. work profile)
+ }
+
out.startTag(null, TAG_PACKAGE);
- ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME,
- mPinnedShortcuts.keyAt(i));
+ ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, pu.packageName);
+ ShortcutService.writeAttr(out, ATTR_PACKAGE_USER_ID, pu.userId);
final ArraySet<String> ids = mPinnedShortcuts.valueAt(i);
final int idSize = ids.size();
@@ -157,8 +192,6 @@
final ShortcutLauncher ret = new ShortcutLauncher(launcherUserId, launcherPackageName,
launcherUserId);
- ShortcutPackageInfo spi = null;
-
ArraySet<String> ids = null;
final int outerDepth = parser.getDepth();
int type;
@@ -172,13 +205,17 @@
if (depth == outerDepth + 1) {
switch (tag) {
case ShortcutPackageInfo.TAG_ROOT:
- spi = ShortcutPackageInfo.loadFromXml(parser);
+ ret.getPackageInfo().loadFromXml(parser, fromBackup);
continue;
case TAG_PACKAGE: {
final String packageName = ShortcutService.parseStringAttribute(parser,
ATTR_PACKAGE_NAME);
+ final int packageUserId = fromBackup ? ownerUserId
+ : ShortcutService.parseIntAttribute(parser,
+ ATTR_PACKAGE_USER_ID, ownerUserId);
ids = new ArraySet<>();
- ret.mPinnedShortcuts.put(packageName, ids);
+ ret.mPinnedShortcuts.put(
+ PackageWithUser.of(packageUserId, packageName), ids);
continue;
}
}
@@ -186,17 +223,17 @@
if (depth == outerDepth + 2) {
switch (tag) {
case TAG_PIN: {
- ids.add(ShortcutService.parseStringAttribute(parser,
- ATTR_VALUE));
+ if (ids == null) {
+ Slog.w(TAG, TAG_PIN + " in invalid place");
+ } else {
+ ids.add(ShortcutService.parseStringAttribute(parser, ATTR_VALUE));
+ }
continue;
}
}
}
ShortcutService.warnForInvalidTag(depth, tag);
}
- if (spi != null) {
- ret.replacePackageInfo(spi);
- }
return ret;
}
@@ -208,6 +245,8 @@
pw.print(getPackageName());
pw.print(" Package user: ");
pw.print(getPackageUserId());
+ pw.print(" Owner user: ");
+ pw.print(getOwnerUserId());
pw.println();
getPackageInfo().dump(s, pw, prefix + " ");
@@ -217,10 +256,14 @@
for (int i = 0; i < size; i++) {
pw.println();
+ final PackageWithUser pu = mPinnedShortcuts.keyAt(i);
+
pw.print(prefix);
pw.print(" ");
pw.print("Package: ");
- pw.println(mPinnedShortcuts.keyAt(i));
+ pw.print(pu.packageName);
+ pw.print(" User: ");
+ pw.println(pu.userId);
final ArraySet<String> ids = mPinnedShortcuts.valueAt(i);
final int idSize = ids.size();
@@ -233,4 +276,9 @@
}
}
}
+
+ @VisibleForTesting
+ ArraySet<String> getAllPinnedShortcutsForTest(String packageName, int packageUserId) {
+ return new ArraySet<>(mPinnedShortcuts.get(PackageWithUser.of(packageUserId, packageName)));
+ }
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 5916202..1076a7a 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -26,6 +26,8 @@
import android.util.ArraySet;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -34,6 +36,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;
@@ -83,7 +86,7 @@
*/
private long mLastResetTime;
- public ShortcutPackage(int packageUserId, String packageName, ShortcutPackageInfo spi) {
+ private ShortcutPackage(int packageUserId, String packageName, ShortcutPackageInfo spi) {
super(packageUserId, packageName, spi != null ? spi : ShortcutPackageInfo.newEmpty());
}
@@ -97,6 +100,19 @@
return getPackageUserId();
}
+ @Override
+ protected void onRestoreBlocked(ShortcutService s) {
+ // Can't restore due to version/signature mismatch. Remove all shortcuts.
+ mShortcuts.clear();
+ }
+
+ @Override
+ protected void onRestored(ShortcutService s) {
+ // Because some launchers may not have been restored (e.g. allowBackup=false),
+ // we need to re-calculate the pinned shortcuts.
+ refreshPinnedFlags(s);
+ }
+
/**
* Note this does *not* provide a correct view to the calling launcher.
*/
@@ -229,20 +245,26 @@
s.getUserShortcutsLocked(getPackageUserId()).getAllLaunchers();
for (int l = launchers.size() - 1; l >= 0; l--) {
+ // Note even if a launcher that hasn't been installed can still pin shortcuts.
+
final ShortcutLauncher launcherShortcuts = launchers.valueAt(l);
final ArraySet<String> pinned = launcherShortcuts.getPinnedShortcutIds(
- getPackageName());
+ getPackageName(), getPackageUserId());
if (pinned == null || pinned.size() == 0) {
continue;
}
for (int i = pinned.size() - 1; i >= 0; i--) {
- final ShortcutInfo si = mShortcuts.get(pinned.valueAt(i));
+ final String id = pinned.valueAt(i);
+ final ShortcutInfo si = mShortcuts.get(id);
if (si == null) {
- s.wtf("Shortcut not found");
- } else {
- si.addFlags(ShortcutInfo.FLAG_PINNED);
+ // This happens if a launcher pinned shortcuts from this package, then backup&
+ // restored, but this package doesn't allow backing up.
+ // In that case the launcher ends up having a dangling pinned shortcuts.
+ // That's fine, when the launcher is restored, we'll fix it.
+ continue;
}
+ si.addFlags(ShortcutInfo.FLAG_PINNED);
}
}
@@ -312,11 +334,15 @@
public void findAll(@NonNull ShortcutService s, @NonNull List<ShortcutInfo> result,
@Nullable Predicate<ShortcutInfo> query, int cloneFlag,
@Nullable String callingLauncher, int launcherUserId) {
+ if (getPackageInfo().isShadow()) {
+ // Restored and the app not installed yet, so don't return any.
+ return;
+ }
// Set of pinned shortcuts by the calling launcher.
final ArraySet<String> pinnedByCallerSet = (callingLauncher == null) ? null
- : s.getLauncherShortcuts(callingLauncher, getPackageUserId(), launcherUserId)
- .getPinnedShortcutIds(getPackageName());
+ : s.getLauncherShortcutsLocked(callingLauncher, getPackageUserId(), launcherUserId)
+ .getPinnedShortcutIds(getPackageName(), getPackageUserId());
for (int i = 0; i < mShortcuts.size(); i++) {
final ShortcutInfo si = mShortcuts.valueAt(i);
@@ -328,7 +354,8 @@
|| ((pinnedByCallerSet != null) && pinnedByCallerSet.contains(si.getId()));
if (!si.isDynamic()) {
if (!si.isPinned()) {
- s.wtf("Shortcut not pinned here");
+ s.wtf("Shortcut not pinned: package " + getPackageName()
+ + ", user=" + getPackageUserId() + ", id=" + si.getId());
continue;
}
if (!isPinnedByCaller) {
@@ -479,7 +506,6 @@
ShortcutService.parseIntAttribute(parser, ATTR_CALL_COUNT);
ret.mLastResetTime =
ShortcutService.parseLongAttribute(parser, ATTR_LAST_RESET);
- ShortcutPackageInfo spi = null;
final int outerDepth = parser.getDepth();
int type;
@@ -493,7 +519,7 @@
if (depth == outerDepth + 1) {
switch (tag) {
case ShortcutPackageInfo.TAG_ROOT:
- spi = ShortcutPackageInfo.loadFromXml(parser);
+ ret.getPackageInfo().loadFromXml(parser, fromBackup);
continue;
case TAG_SHORTCUT:
final ShortcutInfo si = parseShortcut(parser, packageName);
@@ -505,9 +531,6 @@
}
ShortcutService.warnForInvalidTag(depth, tag);
}
- if (spi != null) {
- ret.replacePackageInfo(spi);
- }
return ret;
}
@@ -567,4 +590,9 @@
intentPersistableExtras, weight, extras, lastChangedTimestamp, flags,
iconRes, bitmapPath);
}
+
+ @VisibleForTesting
+ List<ShortcutInfo> getAllShortcutsForTest() {
+ return new ArrayList<>(mShortcuts.values());
+ }
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
index 5f706b8..2c45890 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
@@ -67,10 +67,6 @@
return mIsShadow;
}
- public boolean isInstalled() {
- return !mIsShadow;
- }
-
public void setShadow(boolean shadow) {
mIsShadow = shadow;
}
@@ -79,14 +75,24 @@
return mVersionCode;
}
- public boolean canRestoreTo(PackageInfo target) {
+ public boolean hasSignatures() {
+ return mSigHashes.size() > 0;
+ }
+
+ public boolean canRestoreTo(ShortcutService s, PackageInfo target) {
+ if (!s.shouldBackupApp(target)) {
+ // "allowBackup" was true when backed up, but now false.
+ Slog.w(TAG, "Can't restore: package no longer allows backup");
+ return false;
+ }
if (target.versionCode < mVersionCode) {
- Slog.w(TAG, String.format("Package current version %d < backed up version %d",
+ Slog.w(TAG, String.format(
+ "Can't restore: package current version %d < backed up version %d",
target.versionCode, mVersionCode));
return false;
}
if (!BackupUtils.signaturesMatch(mSigHashes, target)) {
- Slog.w(TAG, "Package signature mismtach");
+ Slog.w(TAG, "Can't restore: Package signature mismatch");
return false;
}
return true;
@@ -106,6 +112,11 @@
}
public void refresh(ShortcutService s, ShortcutPackageItem pkg) {
+ if (mIsShadow) {
+ s.wtf("Attempted to refresh package info for shadow package " + pkg.getPackageName()
+ + ", user=" + pkg.getOwnerUserId());
+ return;
+ }
// Note use mUserId here, rather than userId.
final PackageInfo pi = s.getPackageInfoWithSignatures(
pkg.getPackageName(), pkg.getPackageUserId());
@@ -132,15 +143,17 @@
out.endTag(null, TAG_ROOT);
}
- public static ShortcutPackageInfo loadFromXml(XmlPullParser parser)
+ public void loadFromXml(XmlPullParser parser, boolean fromBackup)
throws IOException, XmlPullParserException {
final int versionCode = ShortcutService.parseIntAttribute(parser, ATTR_VERSION);
- final boolean shadow = ShortcutService.parseBooleanAttribute(parser, ATTR_SHADOW);
+
+ // When restoring from backup, it's always shadow.
+ final boolean shadow =
+ fromBackup || ShortcutService.parseBooleanAttribute(parser, ATTR_SHADOW);
final ArrayList<byte[]> hashes = new ArrayList<>();
-
final int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -163,7 +176,11 @@
}
ShortcutService.warnForInvalidTag(depth, tag);
}
- return new ShortcutPackageInfo(versionCode, hashes, shadow);
+
+ // Successfully loaded; replace the feilds.
+ mVersionCode = versionCode;
+ mIsShadow = shadow;
+ mSigHashes = hashes;
}
public void dump(ShortcutService s, PrintWriter pw, String prefix) {
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
index de2709d..f31dd17 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
@@ -16,6 +16,8 @@
package com.android.server.pm;
import android.annotation.NonNull;
+import android.content.pm.PackageInfo;
+import android.util.Slog;
import com.android.internal.util.Preconditions;
@@ -25,10 +27,12 @@
import java.io.IOException;
abstract class ShortcutPackageItem {
+ private static final String TAG = ShortcutService.TAG;
+
private final int mPackageUserId;
private final String mPackageName;
- private ShortcutPackageInfo mPackageInfo;
+ private final ShortcutPackageInfo mPackageInfo;
protected ShortcutPackageItem(int packageUserId, @NonNull String packageName,
@NonNull ShortcutPackageInfo packageInfo) {
@@ -61,25 +65,62 @@
return mPackageInfo;
}
- /**
- * Should be only used when loading from a file.o
- */
- protected void replacePackageInfo(@NonNull ShortcutPackageInfo packageInfo) {
- mPackageInfo = Preconditions.checkNotNull(packageInfo);
- }
-
public void refreshPackageInfoAndSave(ShortcutService s) {
+ if (mPackageInfo.isShadow()) {
+ return; // Don't refresh for shadow user.
+ }
mPackageInfo.refresh(s, this);
s.scheduleSaveUser(getOwnerUserId());
}
- public void ensureNotShadowAndSave(ShortcutService s) {
- if (mPackageInfo.isShadow()) {
- mPackageInfo.setShadow(false);
- s.scheduleSaveUser(getOwnerUserId());
+ public void attemptToRestoreIfNeededAndSave(ShortcutService s) {
+ if (!mPackageInfo.isShadow()) {
+ return; // Already installed, nothing to do.
}
+ if (!s.isPackageInstalled(mPackageName, mPackageUserId)) {
+ if (ShortcutService.DEBUG) {
+ Slog.d(TAG, String.format("Package still not installed: %s user=%d",
+ mPackageName, mPackageUserId));
+ }
+ return; // Not installed, no need to restore yet.
+ }
+ if (!mPackageInfo.hasSignatures()) {
+ s.wtf("Attempted to restore package " + mPackageName + ", user=" + mPackageUserId
+ + " but signatures not found in the restore data.");
+ onRestoreBlocked(s);
+ return;
+ }
+
+ final PackageInfo pi = s.getPackageInfoWithSignatures(mPackageName, mPackageUserId);
+ if (!mPackageInfo.canRestoreTo(s, pi)) {
+ // Package is now installed, but can't restore. Let the subclass do the cleanup.
+ onRestoreBlocked(s);
+ return;
+ }
+ if (ShortcutService.DEBUG) {
+ Slog.d(TAG, String.format("Restored package: %s/%d on user %d", mPackageName,
+ mPackageUserId, getOwnerUserId()));
+ }
+
+ onRestored(s);
+
+ // Now the package is not shadow.
+ mPackageInfo.setShadow(false);
+
+ s.scheduleSaveUser(mPackageUserId);
}
+ /**
+ * Called when the new package can't be restored because it has a lower version number
+ * or different signatures.
+ */
+ protected abstract void onRestoreBlocked(ShortcutService s);
+
+ /**
+ * Called when the new package is successfully restored.
+ */
+ protected abstract void onRestored(ShortcutService s);
+
public abstract void saveToXml(@NonNull XmlSerializer out, boolean forBackup)
throws IOException, XmlPullParserException;
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 76a2dfa..5c1e7a8 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -46,6 +46,7 @@
import android.net.Uri;
import android.os.Binder;
import android.os.Environment;
+import android.os.FileUtils;
import android.os.Handler;
import android.os.Looper;
import android.os.ParcelFileDescriptor;
@@ -101,6 +102,7 @@
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
import java.util.function.Predicate;
/**
@@ -112,17 +114,16 @@
*
* - Scan and remove orphan bitmaps (just in case).
*
- * - Backup & restore
- *
* - Detect when already registered instances are passed to APIs again, which might break
* internal bitmap handling.
+ *
+ * - Add more call stats.
*/
public class ShortcutService extends IShortcutService.Stub {
static final String TAG = "ShortcutService";
static final boolean DEBUG = false; // STOPSHIP if true
static final boolean DEBUG_LOAD = false; // STOPSHIP if true
- static final boolean ENABLE_DEBUG_COMMAND = true; // STOPSHIP if true
@VisibleForTesting
static final long DEFAULT_RESET_INTERVAL_SEC = 24 * 60 * 60; // 1 day
@@ -262,6 +263,26 @@
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
| PackageManager.MATCH_UNINSTALLED_PACKAGES;
+ // Stats
+ @VisibleForTesting
+ interface Stats {
+ int GET_DEFAULT_HOME = 0;
+ int GET_PACKAGE_INFO = 1;
+ int GET_PACKAGE_INFO_WITH_SIG = 2;
+ int GET_APPLICATION_INFO = 3;
+ int LAUNCHER_PERMISSION_CHECK = 4;
+
+ int COUNT = LAUNCHER_PERMISSION_CHECK + 1;
+ }
+
+ final Object mStatLock = new Object();
+
+ @GuardedBy("mStatLock")
+ private final int[] mCountStats = new int[Stats.COUNT];
+
+ @GuardedBy("mStatLock")
+ private final long[] mDurationStats = new long[Stats.COUNT];
+
public ShortcutService(Context context) {
this(context, BackgroundThread.get().getLooper());
}
@@ -278,6 +299,13 @@
mPackageMonitor.register(context, looper, UserHandle.ALL, /* externalStorage= */ false);
}
+ void logDurationStat(int statId, long start) {
+ synchronized (mStatLock) {
+ mCountStats[statId]++;
+ mDurationStats[statId] += (System.currentTimeMillis() - start);
+ }
+ }
+
/**
* System service lifecycle.
*/
@@ -822,7 +850,7 @@
@GuardedBy("mLock")
@NonNull
- boolean isUserLoadedLocked(@UserIdInt int userId) {
+ private boolean isUserLoadedLocked(@UserIdInt int userId) {
return mUsers.get(userId) != null;
}
@@ -841,19 +869,27 @@
return userPackages;
}
+ void forEachLoadedUserLocked(@NonNull Consumer<ShortcutUser> c) {
+ for (int i = mUsers.size() - 1; i >= 0; i--) {
+ c.accept(mUsers.valueAt(i));
+ }
+ }
+
/** Return the per-user per-package state. */
@GuardedBy("mLock")
@NonNull
ShortcutPackage getPackageShortcutsLocked(
@NonNull String packageName, @UserIdInt int userId) {
- return getUserShortcutsLocked(userId).getPackageShortcuts(packageName);
+ return getUserShortcutsLocked(userId).getPackageShortcuts(this, packageName);
}
@GuardedBy("mLock")
@NonNull
- ShortcutLauncher getLauncherShortcuts(
- @NonNull String packageName, @UserIdInt int userId, @UserIdInt int launcherUserId) {
- return getUserShortcutsLocked(userId).getLauncherShortcuts(packageName, launcherUserId);
+ ShortcutLauncher getLauncherShortcutsLocked(
+ @NonNull String packageName, @UserIdInt int ownerUserId,
+ @UserIdInt int launcherUserId) {
+ return getUserShortcutsLocked(ownerUserId)
+ .getLauncherShortcuts(this, packageName, launcherUserId);
}
// === Caller validation ===
@@ -1212,8 +1248,6 @@
synchronized (mLock) {
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
- ps.ensureNotShadowAndSave(this);
-
// Throttling.
if (!ps.tryApiCall(this)) {
return false;
@@ -1249,8 +1283,6 @@
synchronized (mLock) {
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
- ps.ensureNotShadowAndSave(this);
-
// Throttling.
if (!ps.tryApiCall(this)) {
return false;
@@ -1288,8 +1320,6 @@
synchronized (mLock) {
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
- ps.ensureNotShadowAndSave(this);
-
// Throttling.
if (!ps.tryApiCall(this)) {
return false;
@@ -1422,15 +1452,17 @@
@VisibleForTesting
boolean hasShortcutHostPermissionInner(@NonNull String callingPackage, int userId) {
synchronized (mLock) {
- long start = System.currentTimeMillis();
+ final long start = System.currentTimeMillis();
final ShortcutUser user = getUserShortcutsLocked(userId);
final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
// Default launcher from package manager.
+ final long startGetHomeActivitiesAsUser = System.currentTimeMillis();
final ComponentName defaultLauncher = injectPackageManagerInternal()
.getHomeActivitiesAsUser(allHomeCandidates, userId);
+ logDurationStat(Stats.GET_DEFAULT_HOME, startGetHomeActivitiesAsUser);
ComponentName detected;
if (defaultLauncher != null) {
@@ -1473,10 +1505,8 @@
lastPriority = ri.priority;
}
}
- final long end = System.currentTimeMillis();
- if (DEBUG) {
- Slog.v(TAG, String.format("hasShortcutPermission took %d ms", end - start));
- }
+ logDurationStat(Stats.LAUNCHER_PERMISSION_CHECK, start);
+
if (detected != null) {
if (DEBUG) {
Slog.v(TAG, "Detected launcher: " + detected);
@@ -1492,10 +1522,17 @@
// === House keeping ===
+ /**
+ * Remove all the information associated with a package. This will really remove all the
+ * information, including the restore information (i.e. it'll remove packages even if they're
+ * shadow).
+ */
@VisibleForTesting
void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId) {
-
- // TODO Don't remove shadow packages' information.
+ if (isPackageInstalled(packageName, packageUserId)) {
+ wtf("Package " + packageName + " is still installed for user " + packageUserId);
+ return;
+ }
final boolean wasUserLoaded = isUserLoadedLocked(owningUserId);
@@ -1504,7 +1541,7 @@
// First, remove the package from the package list (if the package is a publisher).
if (packageUserId == owningUserId) {
- if (mUser.getPackages().remove(packageName) != null) {
+ if (mUser.removePackage(packageName) != null) {
doNotify = true;
}
}
@@ -1515,12 +1552,12 @@
// Then remove pinned shortcuts from all launchers.
final ArrayMap<PackageWithUser, ShortcutLauncher> launchers = mUser.getAllLaunchers();
for (int i = launchers.size() - 1; i >= 0; i--) {
- launchers.valueAt(i).cleanUpPackage(packageName);
+ launchers.valueAt(i).cleanUpPackage(packageName, packageUserId);
}
// Now there may be orphan shortcuts because we removed pinned shortucts at the previous
// step. Remove them too.
- for (int i = mUser.getPackages().size() - 1; i >= 0; i--) {
- mUser.getPackages().valueAt(i).refreshPinnedFlags(this);
+ for (int i = mUser.getAllPackages().size() - 1; i >= 0; i--) {
+ mUser.getAllPackages().valueAt(i).refreshPinnedFlags(this);
}
scheduleSaveUser(owningUserId);
@@ -1539,6 +1576,7 @@
* Entry point from {@link LauncherApps}.
*/
private class LocalService extends ShortcutServiceInternal {
+
@Override
public List<ShortcutInfo> getShortcuts(int launcherUserId,
@NonNull String callingPackage, long changedSince,
@@ -1551,13 +1589,16 @@
: ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO;
synchronized (mLock) {
+ getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+ .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
if (packageName != null) {
getShortcutsInnerLocked(launcherUserId,
callingPackage, packageName, changedSince,
componentName, queryFlags, userId, ret, cloneFlag);
} else {
final ArrayMap<String, ShortcutPackage> packages =
- getUserShortcutsLocked(userId).getPackages();
+ getUserShortcutsLocked(userId).getAllPackages();
for (int i = packages.size() - 1; i >= 0; i--) {
getShortcutsInnerLocked(launcherUserId,
callingPackage, packages.keyAt(i), changedSince,
@@ -1601,6 +1642,9 @@
final ArrayList<ShortcutInfo> ret = new ArrayList<>(ids.size());
final ArraySet<String> idSet = new ArraySet<>(ids);
synchronized (mLock) {
+ getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+ .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
getPackageShortcutsLocked(packageName, userId).findAll(
ShortcutService.this, ret,
(ShortcutInfo si) -> idSet.contains(si.getId()),
@@ -1616,13 +1660,16 @@
Preconditions.checkStringNotEmpty(shortcutId, "shortcutId");
synchronized (mLock) {
+ getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+ .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
final ShortcutInfo si = getShortcutInfoLocked(
launcherUserId, callingPackage, packageName, shortcutId, userId);
return si != null && si.isPinned();
}
}
- public ShortcutInfo getShortcutInfoLocked(
+ private ShortcutInfo getShortcutInfoLocked(
int launcherUserId, @NonNull String callingPackage,
@NonNull String packageName, @NonNull String shortcutId, int userId) {
Preconditions.checkStringNotEmpty(packageName, "packageName");
@@ -1646,9 +1693,8 @@
synchronized (mLock) {
final ShortcutLauncher launcher =
- getLauncherShortcuts(callingPackage, userId, launcherUserId);
-
- launcher.ensureNotShadowAndSave(ShortcutService.this);
+ getLauncherShortcutsLocked(callingPackage, userId, launcherUserId);
+ launcher.attemptToRestoreIfNeededAndSave(ShortcutService.this);
launcher.pinShortcuts(
ShortcutService.this, userId, packageName, shortcutIds);
@@ -1665,6 +1711,9 @@
Preconditions.checkStringNotEmpty(shortcutId, "shortcutId can't be empty");
synchronized (mLock) {
+ getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+ .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
// Make sure the shortcut is actually visible to the launcher.
final ShortcutInfo si = getShortcutInfoLocked(
launcherUserId, callingPackage, packageName, shortcutId, userId);
@@ -1690,6 +1739,9 @@
Preconditions.checkNotNull(shortcut, "shortcut");
synchronized (mLock) {
+ getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+ .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
final ShortcutInfo shortcutInfo = getPackageShortcutsLocked(
shortcut.getPackageName(), userId).findShortcutById(shortcut.getId());
return (shortcutInfo != null && shortcutInfo.hasIconResource())
@@ -1704,6 +1756,9 @@
Preconditions.checkNotNull(shortcutIn, "shortcut");
synchronized (mLock) {
+ getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+ .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
final ShortcutInfo shortcutInfo = getPackageShortcutsLocked(
shortcutIn.getPackageName(), userId).findShortcutById(shortcutIn.getId());
if (shortcutInfo == null || !shortcutInfo.hasIconFile()) {
@@ -1757,28 +1812,28 @@
* perform cleanup.
*/
@VisibleForTesting
- void cleanupGonePackages(@UserIdInt int userId) {
+ void cleanupGonePackages(@UserIdInt int ownerUserId) {
if (DEBUG) {
- Slog.d(TAG, "cleanupGonePackages() userId=" + userId);
+ Slog.d(TAG, "cleanupGonePackages() ownerUserId=" + ownerUserId);
}
final ArrayList<PackageWithUser> gonePackages = new ArrayList<>();
synchronized (mLock) {
- final ShortcutUser user = getUserShortcutsLocked(userId);
+ final ShortcutUser user = getUserShortcutsLocked(ownerUserId);
user.forAllPackageItems(spi -> {
if (spi.getPackageInfo().isShadow()) {
return; // Don't delete shadow information.
}
if (isPackageInstalled(spi.getPackageName(), spi.getPackageUserId())) {
- return;
+ return; // Package not gone.
}
gonePackages.add(PackageWithUser.of(spi));
});
if (gonePackages.size() > 0) {
for (int i = gonePackages.size() - 1; i >= 0; i--) {
final PackageWithUser pu = gonePackages.get(i);
- cleanUpPackageLocked(pu.packageName, userId, pu.userId);
+ cleanUpPackageLocked(pu.packageName, ownerUserId, pu.userId);
}
}
}
@@ -1789,7 +1844,8 @@
Slog.d(TAG, String.format("handlePackageAdded: %s user=%d", packageName, userId));
}
synchronized (mLock) {
- getUserShortcutsLocked(userId).unshadowPackage(this, packageName, userId);
+ forEachLoadedUserLocked(user ->
+ user.attemptToRestoreIfNeededAndSave(this, packageName, userId));
}
}
@@ -1798,18 +1854,20 @@
Slog.d(TAG, String.format("handlePackageUpdateFinished: %s user=%d",
packageName, userId));
}
-
synchronized (mLock) {
- getUserShortcutsLocked(userId).unshadowPackage(this, packageName, userId);
+ forEachLoadedUserLocked(user ->
+ user.attemptToRestoreIfNeededAndSave(this, packageName, userId));
}
}
- private void handlePackageRemoved(String packageName, @UserIdInt int userId) {
+ private void handlePackageRemoved(String packageName, @UserIdInt int packageUserId) {
if (DEBUG) {
- Slog.d(TAG, String.format("handlePackageRemoved: %s user=%d", packageName, userId));
+ Slog.d(TAG, String.format("handlePackageRemoved: %s user=%d", packageName,
+ packageUserId));
}
synchronized (mLock) {
- cleanUpPackageLocked(packageName, userId, userId);
+ forEachLoadedUserLocked(user ->
+ cleanUpPackageLocked(packageName, user.getUserId(), packageUserId));
}
}
@@ -1836,6 +1894,7 @@
@VisibleForTesting
PackageInfo injectPackageInfo(String packageName, @UserIdInt int userId,
boolean getSignatures) {
+ final long start = System.currentTimeMillis();
final long token = injectClearCallingIdentity();
try {
return mIPackageManager.getPackageInfo(packageName, PACKAGE_MATCH_FLAGS
@@ -1847,11 +1906,16 @@
return null;
} finally {
injectRestoreCallingIdentity(token);
+
+ logDurationStat(
+ (getSignatures ? Stats.GET_PACKAGE_INFO_WITH_SIG : Stats.GET_PACKAGE_INFO),
+ start);
}
}
@VisibleForTesting
ApplicationInfo injectApplicationInfo(String packageName, @UserIdInt int userId) {
+ final long start = System.currentTimeMillis();
final long token = injectClearCallingIdentity();
try {
return mIPackageManager.getApplicationInfo(packageName, PACKAGE_MATCH_FLAGS, userId);
@@ -1861,6 +1925,8 @@
return null;
} finally {
injectRestoreCallingIdentity(token);
+
+ logDurationStat(Stats.GET_APPLICATION_INFO, start);
}
}
@@ -1869,7 +1935,7 @@
return (ai != null) && ((ai.flags & flags) == flags);
}
- private boolean isPackageInstalled(String packageName, int userId) {
+ boolean isPackageInstalled(String packageName, int userId) {
return isApplicationFlagSet(packageName, userId, ApplicationInfo.FLAG_INSTALLED);
}
@@ -1879,8 +1945,12 @@
return isApplicationFlagSet(packageName, userId, ApplicationInfo.FLAG_ALLOW_BACKUP);
}
+ boolean shouldBackupApp(PackageInfo pi) {
+ return (pi.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0;
+ }
+
@Override
- public byte[] getBackupPayload(@UserIdInt int userId) throws RemoteException {
+ public byte[] getBackupPayload(@UserIdInt int userId) {
enforceSystem();
if (DEBUG) {
Slog.d(TAG, "Backing up user " + userId);
@@ -1908,7 +1978,7 @@
}
@Override
- public void applyRestore(byte[] payload, @UserIdInt int userId) throws RemoteException {
+ public void applyRestore(byte[] payload, @UserIdInt int userId) {
enforceSystem();
if (DEBUG) {
Slog.d(TAG, "Restoring user " + userId);
@@ -1923,6 +1993,15 @@
}
synchronized (mLock) {
mUsers.put(userId, user);
+
+ // Then purge all the save images.
+ final File bitmapPath = getUserBitmapFilePath(userId);
+ final boolean success = FileUtils.deleteContents(bitmapPath);
+ if (!success) {
+ Slog.w(TAG, "Failed to delete " + bitmapPath);
+ }
+
+ saveUserLocked(userId);
}
}
@@ -1974,9 +2053,19 @@
pw.print(" Icon format: ");
pw.print(mIconPersistFormat);
pw.print(" Icon quality: ");
- pw.print(mIconPersistQuality);
+ pw.println(mIconPersistQuality);
pw.println();
+ pw.println(" Stats:");
+ synchronized (mStatLock) {
+ final String p = " ";
+ dumpStatLS(pw, p, Stats.GET_DEFAULT_HOME, "getHomeActivities()");
+ dumpStatLS(pw, p, Stats.LAUNCHER_PERMISSION_CHECK, "Launcher permission check");
+
+ dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO, "getPackageInfo()");
+ dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO_WITH_SIG, "getPackageInfo(SIG)");
+ dumpStatLS(pw, p, Stats.GET_APPLICATION_INFO, "getApplicationInfo");
+ }
for (int i = 0; i < mUsers.size(); i++) {
pw.println();
@@ -1991,6 +2080,15 @@
return tobj.format("%Y-%m-%d %H:%M:%S");
}
+ private void dumpStatLS(PrintWriter pw, String prefix, int statId, String label) {
+ pw.print(prefix);
+ final int count = mCountStats[statId];
+ final long dur = mDurationStats[statId];
+ pw.println(String.format("%s: count=%d, total=%dms, avg=%.1fms",
+ label, count, dur,
+ (count == 0 ? 0 : ((double) dur) / count)));
+ }
+
// === Shell support ===
@Override
@@ -2061,6 +2159,9 @@
case "refresh-default-launcher":
handleRefreshDefaultLauncher();
break;
+ case "unload-user":
+ handleUnloadUser();
+ break;
default:
return handleDefaultCommands(cmd);
}
@@ -2098,6 +2199,10 @@
pw.println("cmd shortcut refresh-default-launcher [--user USER_ID]");
pw.println(" Refresh the cached default launcher");
pw.println();
+ pw.println("cmd shortcut unload-user [--user USER_ID]");
+ pw.println(" Unload a user from the memory");
+ pw.println(" (This should not affect any observable behavior)");
+ pw.println();
}
private int handleResetThrottling() throws CommandException {
@@ -2169,6 +2274,12 @@
clearLauncher();
showLauncher();
}
+
+ private void handleUnloadUser() throws CommandException {
+ parseOptions(/* takeUser =*/ true);
+
+ ShortcutService.this.handleCleanupUser(mUserId);
+ }
}
// === Unit test support ===
@@ -2202,9 +2313,10 @@
}
final void wtf(String message) {
- Slog.wtf(TAG, message, /* exception= */ null);
+ wtf( message, /* exception= */ null);
}
+ // Injection point.
void wtf(String message, Exception e) {
Slog.wtf(TAG, message, e);
}
@@ -2275,7 +2387,7 @@
final ShortcutUser user = mUsers.get(userId);
if (user == null) return null;
- final ShortcutPackage pkg = user.getPackages().get(packageName);
+ final ShortcutPackage pkg = user.getAllPackages().get(packageName);
if (pkg == null) return null;
return pkg.findShortcutById(shortcutId);
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 487558f..593f607 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -53,8 +53,8 @@
this.packageName = Preconditions.checkNotNull(packageName);
}
- public static PackageWithUser of(int launcherUserId, String packageName) {
- return new PackageWithUser(launcherUserId, packageName);
+ public static PackageWithUser of(int userId, String packageName) {
+ return new PackageWithUser(userId, packageName);
}
public static PackageWithUser of(ShortcutPackageItem spi) {
@@ -78,12 +78,12 @@
@Override
public String toString() {
- return String.format("{Launcher: %d, %s}", userId, packageName);
+ return String.format("{Package: %d, %s}", userId, packageName);
}
}
@UserIdInt
- final int mUserId;
+ private final int mUserId;
private final ArrayMap<String, ShortcutPackage> mPackages = new ArrayMap<>();
@@ -95,10 +95,18 @@
mUserId = userId;
}
- public ArrayMap<String, ShortcutPackage> getPackages() {
+ public int getUserId() {
+ return mUserId;
+ }
+
+ public ArrayMap<String, ShortcutPackage> getAllPackages() {
return mPackages;
}
+ public ShortcutPackage removePackage(@NonNull String packageName) {
+ return mPackages.remove(packageName);
+ }
+
public ArrayMap<PackageWithUser, ShortcutLauncher> getAllLaunchers() {
return mLaunchers;
}
@@ -113,22 +121,26 @@
return mLaunchers.remove(PackageWithUser.of(packageUserId, packageName));
}
- public ShortcutPackage getPackageShortcuts(@NonNull String packageName) {
+ public ShortcutPackage getPackageShortcuts(ShortcutService s, @NonNull String packageName) {
ShortcutPackage ret = mPackages.get(packageName);
if (ret == null) {
ret = new ShortcutPackage(mUserId, packageName);
mPackages.put(packageName, ret);
+ } else {
+ ret.attemptToRestoreIfNeededAndSave(s);
}
return ret;
}
- public ShortcutLauncher getLauncherShortcuts(@NonNull String packageName,
+ public ShortcutLauncher getLauncherShortcuts(ShortcutService s, @NonNull String packageName,
@UserIdInt int launcherUserId) {
final PackageWithUser key = PackageWithUser.of(launcherUserId, packageName);
ShortcutLauncher ret = mLaunchers.get(key);
if (ret == null) {
ret = new ShortcutLauncher(mUserId, packageName, launcherUserId);
mLaunchers.put(key, ret);
+ } else {
+ ret.attemptToRestoreIfNeededAndSave(s);
}
return ret;
}
@@ -148,14 +160,6 @@
}
}
- public void unshadowPackage(ShortcutService s, @NonNull String packageName,
- @UserIdInt int packageUserId) {
- forPackageItem(packageName, packageUserId, spi -> {
- Slog.i(TAG, String.format("Restoring for %s, user=%d", packageName, packageUserId));
- spi.ensureNotShadowAndSave(s);
- });
- }
-
public void forPackageItem(@NonNull String packageName, @UserIdInt int packageUserId,
Consumer<ShortcutPackageItem> callback) {
forAllPackageItems(spi -> {
@@ -166,6 +170,13 @@
});
}
+ public void attemptToRestoreIfNeededAndSave(ShortcutService s, @NonNull String packageName,
+ @UserIdInt int packageUserId) {
+ forPackageItem(packageName, packageUserId, spi -> {
+ spi.attemptToRestoreIfNeededAndSave(s);
+ });
+ }
+
public void saveToXml(ShortcutService s, XmlSerializer out, boolean forBackup)
throws IOException, XmlPullParserException {
out.startTag(null, TAG_ROOT);
@@ -229,7 +240,7 @@
s, parser, userId, fromBackup);
// Don't use addShortcut(), we don't need to save the icon.
- ret.getPackages().put(shortcuts.getPackageName(), shortcuts);
+ ret.mPackages.put(shortcuts.getPackageName(), shortcuts);
continue;
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 88f4190..06a91fb 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -500,6 +500,9 @@
if (mRemovingUserIds.get(profile.id)) {
continue;
}
+ if (profile.partial) {
+ continue;
+ }
users.add(userWithName(profile));
}
return users;
@@ -573,12 +576,26 @@
private void broadcastProfileAvailabilityChanges(UserHandle profileHandle,
UserHandle parentHandle, boolean inQuietMode) {
- Intent intent = new Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
+ Intent intent = new Intent();
+ if (inQuietMode) {
+ intent.setAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
+ } else {
+ intent.setAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
+ }
intent.putExtra(Intent.EXTRA_QUIET_MODE, inQuietMode);
intent.putExtra(Intent.EXTRA_USER, profileHandle);
intent.putExtra(Intent.EXTRA_USER_HANDLE, profileHandle.getIdentifier());
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendBroadcastAsUser(intent, parentHandle);
+
+ //TODO: remove once Launcher3 is updated.
+ Intent oldIntent = new Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
+ oldIntent.putExtra(Intent.EXTRA_QUIET_MODE, inQuietMode);
+ oldIntent.putExtra(Intent.EXTRA_USER, profileHandle);
+ oldIntent.putExtra(Intent.EXTRA_USER_HANDLE, profileHandle.getIdentifier());
+ oldIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcastAsUser(oldIntent, parentHandle);
+
}
@Override
@@ -1941,6 +1958,7 @@
long now = System.currentTimeMillis();
userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;
userInfo.partial = true;
+ userInfo.lastLoggedInFingerprint = Build.FINGERPRINT;
userData = new UserData();
userData.info = userInfo;
mUsers.put(userId, userData);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 747e31e..14d0457 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3107,10 +3107,8 @@
return -1;
}
} else if (keyCode == KeyEvent.KEYCODE_SLASH && event.isMetaPressed()) {
- if (down) {
- if (repeatCount == 0) {
- toggleKeyboardShortcutsMenu(event.getDeviceId());
- }
+ if (down && repeatCount == 0 && !isKeyguardLocked()) {
+ toggleKeyboardShortcutsMenu(event.getDeviceId());
}
} else if (keyCode == KeyEvent.KEYCODE_ASSIST) {
if (down) {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index ff5a0f9..7570960 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -538,7 +538,10 @@
@Override
public void onBootPhase(int phase) {
synchronized (mLock) {
- if (phase == PHASE_BOOT_COMPLETED) {
+ if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+ incrementBootCount();
+
+ } else if (phase == PHASE_BOOT_COMPLETED) {
final long now = SystemClock.uptimeMillis();
mBootCompleted = true;
mDirty |= DIRTY_BOOT_COMPLETED;
@@ -553,8 +556,6 @@
}
}
mBootCompletedRunnables = null;
-
- incrementBootCount();
}
}
}
diff --git a/services/core/java/com/android/server/vr/EnabledComponentsObserver.java b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
index 1363fb9..eb926c1 100644
--- a/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
+++ b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
@@ -227,10 +227,11 @@
return userIds;
}
- private ArraySet<ComponentName> loadComponentNamesForUser(int userId) {
+ public static ArraySet<ComponentName> loadComponentNames(PackageManager pm, int userId,
+ String serviceName, String permissionName) {
+
ArraySet<ComponentName> installed = new ArraySet<>();
- PackageManager pm = mContext.getPackageManager();
- Intent queryIntent = new Intent(mServiceName);
+ Intent queryIntent = new Intent(serviceName);
List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
queryIntent,
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
@@ -241,10 +242,10 @@
ServiceInfo info = resolveInfo.serviceInfo;
ComponentName component = new ComponentName(info.packageName, info.name);
- if (!mServicePermission.equals(info.permission)) {
+ if (!permissionName.equals(info.permission)) {
Slog.w(TAG, "Skipping service " + info.packageName + "/" + info.name
+ ": it does not require the permission "
- + mServicePermission);
+ + permissionName);
continue;
}
installed.add(component);
@@ -253,6 +254,11 @@
return installed;
}
+ private ArraySet<ComponentName> loadComponentNamesForUser(int userId) {
+ return loadComponentNames(mContext.getPackageManager(), userId, mServiceName,
+ mServicePermission);
+ }
+
private ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
int userId) {
final ContentResolver cr = mContext.getContentResolver();
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index aa6f59e..c572e76 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -16,16 +16,23 @@
package com.android.server.vr;
import android.app.AppOpsManager;
+import android.app.NotificationManager;
import android.annotation.NonNull;
-import android.content.Context;
import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Looper;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.provider.Settings;
+import android.service.notification.NotificationListenerService;
import android.service.vr.IVrListener;
import android.service.vr.VrListenerService;
import android.util.ArraySet;
@@ -38,7 +45,9 @@
import com.android.server.utils.ManagedApplicationService;
import com.android.server.utils.ManagedApplicationService.BinderChecker;
+import java.lang.StringBuilder;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Objects;
import java.util.Set;
@@ -53,8 +62,8 @@
* hardware/libhardware/modules/vr
* <p/>
* In general applications may enable or disable VR mode by calling
- * {@link android.app.Activity#setVrMode)}. An application may also implement a service to be run
- * while in VR mode by implementing {@link android.service.vr.VrListenerService}.
+ * {@link android.app.Activity#setVrModeEnabled)}. An application may also implement a service to
+ * be run while in VR mode by implementing {@link android.service.vr.VrListenerService}.
*
* @see {@link android.service.vr.VrListenerService}
* @see {@link com.android.server.vr.VrManagerInternal}
@@ -74,13 +83,18 @@
private final IBinder mOverlayToken = new Binder();
// State protected by mLock
- private boolean mVrModeEnabled = false;
+ private boolean mVrModeEnabled;
private final Set<VrStateListener> mListeners = new ArraySet<>();
private EnabledComponentsObserver mComponentObserver;
private ManagedApplicationService mCurrentVrService;
private Context mContext;
private ComponentName mCurrentVrModeComponent;
private int mCurrentVrModeUser;
+ private boolean mWasDefaultGranted;
+ private boolean mGuard;
+ private final ArraySet<String> mPreviousToggledListenerSettings = new ArraySet<>();
+ private String mPreviousNotificationPolicyAccessPackage;
+ private String mPreviousManageOverlayPackage;
private static final BinderChecker sBinderChecker = new BinderChecker() {
@Override
@@ -239,62 +253,271 @@
*
* @return {@code true} if the component/user combination specified is valid.
*/
- private boolean updateCurrentVrServiceLocked(boolean enabled,
- @NonNull ComponentName component, int userId, ComponentName calling) {
+ private boolean updateCurrentVrServiceLocked(boolean enabled, @NonNull ComponentName component,
+ int userId, ComponentName calling) {
boolean sendUpdatedCaller = false;
+ final long identity = Binder.clearCallingIdentity();
+ try {
- boolean validUserComponent = (mComponentObserver.isValid(component, userId) ==
- EnabledComponentsObserver.NO_ERROR);
+ boolean validUserComponent = (mComponentObserver.isValid(component, userId) ==
+ EnabledComponentsObserver.NO_ERROR);
- // Always send mode change events.
- changeVrModeLocked(enabled, (enabled && validUserComponent) ? component : null);
+ // Always send mode change events.
+ changeVrModeLocked(enabled, (enabled && validUserComponent) ? component : null);
- if (!enabled || !validUserComponent) {
- // Unbind whatever is running
- if (mCurrentVrService != null) {
- Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " +
- mCurrentVrService.getUserId());
- mCurrentVrService.disconnect();
- mCurrentVrService = null;
- }
- } else {
- if (mCurrentVrService != null) {
- // Unbind any running service that doesn't match the component/user selection
- if (mCurrentVrService.disconnectIfNotMatching(component, userId)) {
+ if (!enabled || !validUserComponent) {
+ // Unbind whatever is running
+ if (mCurrentVrService != null) {
Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " +
- mCurrentVrService.getUserId());
+ mCurrentVrService.getUserId());
+ mCurrentVrService.disconnect();
+ disableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
+ new UserHandle(mCurrentVrService.getUserId()));
+ mCurrentVrService = null;
+ }
+ } else {
+ if (mCurrentVrService != null) {
+ // Unbind any running service that doesn't match the component/user selection
+ if (mCurrentVrService.disconnectIfNotMatching(component, userId)) {
+ Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() +
+ " for user " + mCurrentVrService.getUserId());
+ disableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
+ new UserHandle(mCurrentVrService.getUserId()));
+ createAndConnectService(component, userId);
+ enableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
+ new UserHandle(mCurrentVrService.getUserId()));
+ sendUpdatedCaller = true;
+ }
+ // The service with the correct component/user is bound
+ } else {
+ // Nothing was previously running, bind a new service
createAndConnectService(component, userId);
+ enableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
+ new UserHandle(mCurrentVrService.getUserId()));
sendUpdatedCaller = true;
}
- // The service with the correct component/user is bound
- } else {
- // Nothing was previously running, bind a new service
- createAndConnectService(component, userId);
+ }
+
+ if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent)) {
+ mCurrentVrModeComponent = calling;
+ mCurrentVrModeUser = userId;
sendUpdatedCaller = true;
}
+
+ if (mCurrentVrService != null && sendUpdatedCaller) {
+ final ComponentName c = mCurrentVrModeComponent;
+ mCurrentVrService.sendEvent(new PendingEvent() {
+ @Override
+ public void runEvent(IInterface service) throws RemoteException {
+ IVrListener l = (IVrListener) service;
+ l.focusedActivityChanged(c);
+ }
+ });
+ }
+
+ return validUserComponent;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Enable the permission given in {@link #IMPLIED_VR_LISTENER_PERMISSIONS} for the given
+ * component package and user.
+ *
+ * @param component the component whose package should be enabled.
+ * @param userId the user that owns the given component.
+ */
+ private void enableImpliedPermissionsLocked(ComponentName component, UserHandle userId) {
+ if (mGuard) {
+ // Impossible
+ throw new IllegalStateException("Enabling permissions without disabling.");
+ }
+ mGuard = true;
+
+ PackageManager pm = mContext.getPackageManager();
+
+ String pName = component.getPackageName();
+ if (pm == null) {
+ Slog.e(TAG, "Couldn't set implied permissions for " + pName +
+ ", PackageManager isn't running");
+ return;
+ }
+
+ ApplicationInfo info = null;
+ try {
+ info = pm.getApplicationInfo(pName, PackageManager.GET_META_DATA);
+ } catch (NameNotFoundException e) {
+ }
+
+ if (info == null) {
+ Slog.e(TAG, "Couldn't set implied permissions for " + pName + ", no such package.");
+ return;
+ }
+
+ if (!(info.isSystemApp() || info.isUpdatedSystemApp())) {
+ return; // Application is not pre-installed, avoid setting implied permissions
+ }
+
+ mWasDefaultGranted = true;
+
+ grantOverlayAccess(pName, userId);
+ grantNotificationPolicyAccess(pName);
+ grantNotificationListenerAccess(pName, userId);
+ }
+
+ /**
+ * Disable the permission given in {@link #IMPLIED_VR_LISTENER_PERMISSIONS} for the given
+ * component package and user.
+ *
+ * @param component the component whose package should be disabled.
+ * @param userId the user that owns the given component.
+ */
+ private void disableImpliedPermissionsLocked(ComponentName component, UserHandle userId) {
+ if (!mGuard) {
+ // Impossible
+ throw new IllegalStateException("Disabling permissions without enabling.");
+ }
+ mGuard = false;
+
+ PackageManager pm = mContext.getPackageManager();
+
+ if (pm == null) {
+ Slog.e(TAG, "Couldn't remove implied permissions for " + component +
+ ", PackageManager isn't running");
+ return;
+ }
+
+ String pName = component.getPackageName();
+ if (mWasDefaultGranted) {
+ revokeOverlayAccess(userId);
+ revokeNotificationPolicyAccess(pName);
+ revokeNotificiationListenerAccess();
+ mWasDefaultGranted = false;
+ }
+
+ }
+
+ private void grantOverlayAccess(String pkg, UserHandle userId) {
+ PackageManager pm = mContext.getPackageManager();
+ boolean prev = (PackageManager.PERMISSION_GRANTED ==
+ pm.checkPermission(android.Manifest.permission.SYSTEM_ALERT_WINDOW, pkg));
+ mPreviousManageOverlayPackage = null;
+ if (!prev) {
+ pm.grantRuntimePermission(pkg, android.Manifest.permission.SYSTEM_ALERT_WINDOW,
+ userId);
+ mPreviousManageOverlayPackage = pkg;
+ }
+ }
+
+ private void revokeOverlayAccess(UserHandle userId) {
+ PackageManager pm = mContext.getPackageManager();
+ if (mPreviousManageOverlayPackage != null) {
+ pm.revokeRuntimePermission(mPreviousManageOverlayPackage,
+ android.Manifest.permission.SYSTEM_ALERT_WINDOW, userId);
+ mPreviousManageOverlayPackage = null;
+ }
+ }
+
+
+ private void grantNotificationPolicyAccess(String pkg) {
+ NotificationManager nm = mContext.getSystemService(NotificationManager.class);
+ boolean prev = nm.isNotificationPolicyAccessGrantedForPackage(pkg);
+ mPreviousNotificationPolicyAccessPackage = null;
+ if (!prev) {
+ mPreviousNotificationPolicyAccessPackage = pkg;
+ nm.setNotificationPolicyAccessGranted(pkg, true);
+ }
+ }
+
+ private void revokeNotificationPolicyAccess(String pkg) {
+ NotificationManager nm = mContext.getSystemService(NotificationManager.class);
+ if (mPreviousNotificationPolicyAccessPackage != null) {
+ nm.setNotificationPolicyAccessGranted(mPreviousNotificationPolicyAccessPackage, false);
+ mPreviousNotificationPolicyAccessPackage = null;
+ }
+ }
+
+ private void grantNotificationListenerAccess(String pkg, UserHandle userId) {
+ PackageManager pm = mContext.getPackageManager();
+ ArraySet<ComponentName> possibleServices = EnabledComponentsObserver.loadComponentNames(pm,
+ userId.getIdentifier(), NotificationListenerService.SERVICE_INTERFACE,
+ android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE);
+ ContentResolver resolver = mContext.getContentResolver();
+
+ ArraySet<String> current = getCurrentNotifListeners(resolver);
+
+ mPreviousToggledListenerSettings.clear();
+
+ for (ComponentName c : possibleServices) {
+ String flatName = c.flattenToString();
+ if (Objects.equals(c.getPackageName(), pkg)
+ && !current.contains(flatName)) {
+ mPreviousToggledListenerSettings.add(flatName);
+ current.add(flatName);
+ }
}
- if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent)) {
- mCurrentVrModeComponent = calling;
- mCurrentVrModeUser = userId;
- sendUpdatedCaller = true;
+ if (current.size() > 0) {
+ String flatSettings = formatSettings(current);
+ Settings.Secure.putString(resolver, Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
+ flatSettings);
}
-
- if (mCurrentVrService != null && sendUpdatedCaller) {
- final ComponentName c = mCurrentVrModeComponent;
- mCurrentVrService.sendEvent(new PendingEvent() {
- @Override
- public void runEvent(IInterface service) throws RemoteException {
- IVrListener l = (IVrListener) service;
- l.focusedActivityChanged(c);
- }
- });
- }
-
- return validUserComponent;
}
+ private void revokeNotificiationListenerAccess() {
+ if (mPreviousToggledListenerSettings.isEmpty()) {
+ return;
+ }
+
+ ContentResolver resolver = mContext.getContentResolver();
+ ArraySet<String> current = getCurrentNotifListeners(resolver);
+
+ current.removeAll(mPreviousToggledListenerSettings);
+ mPreviousToggledListenerSettings.clear();
+
+ String flatSettings = formatSettings(current);
+ Settings.Secure.putString(resolver, Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
+ flatSettings);
+ }
+
+ private ArraySet<String> getCurrentNotifListeners(ContentResolver resolver) {
+ String flat = Settings.Secure.getString(resolver,
+ Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
+
+ ArraySet<String> current = new ArraySet<>();
+ if (flat != null) {
+ String[] allowed = flat.split(":");
+ for (String s : allowed) {
+ current.add(s);
+ }
+ }
+ return current;
+ }
+
+ private static String formatSettings(Collection<String> c) {
+ if (c == null || c.isEmpty()) {
+ return "";
+ }
+
+ StringBuilder b = new StringBuilder();
+ boolean start = true;
+ for (String s : c) {
+ if ("".equals(s)) {
+ continue;
+ }
+ if (!start) {
+ b.append(':');
+ }
+ b.append(s);
+ start = false;
+ }
+ return b.toString();
+ }
+
+
+
private void createAndConnectService(@NonNull ComponentName component, int userId) {
mCurrentVrService = VrManagerService.create(mContext, component, userId);
mCurrentVrService.connect();
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 4848523..fb3c6ec 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -16,8 +16,8 @@
package com.android.server.wallpaper;
-import static android.app.WallpaperManager.FLAG_SET_SYSTEM;
-import static android.app.WallpaperManager.FLAG_SET_LOCK;
+import static android.app.WallpaperManager.FLAG_SYSTEM;
+import static android.app.WallpaperManager.FLAG_LOCK;
import static android.os.ParcelFileDescriptor.*;
import android.app.ActivityManager;
@@ -231,7 +231,7 @@
false, wallpaper, null);
}
if (lockWallpaperChanged
- || (wallpaper.whichPending & FLAG_SET_LOCK) != 0) {
+ || (wallpaper.whichPending & FLAG_LOCK) != 0) {
if (DEBUG) {
Slog.i(TAG, "Lock-relevant wallpaper changed");
}
@@ -505,7 +505,7 @@
&& mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME
> SystemClock.uptimeMillis()) {
Slog.w(TAG, "Reverting to built-in wallpaper!");
- clearWallpaperLocked(true, FLAG_SET_SYSTEM, mWallpaper.userId, null);
+ clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null);
} else {
mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
}
@@ -584,7 +584,7 @@
if (!bindWallpaperComponentLocked(comp, false, false,
wallpaper, null)) {
Slog.w(TAG, "Wallpaper no longer available; reverting to default");
- clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, null);
+ clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
}
}
}
@@ -664,7 +664,7 @@
if (doit) {
Slog.w(TAG, "Wallpaper uninstalled, removing: "
+ wallpaper.wallpaperComponent);
- clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, null);
+ clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
}
}
}
@@ -684,7 +684,7 @@
} catch (NameNotFoundException e) {
Slog.w(TAG, "Wallpaper component gone, removing: "
+ wallpaper.wallpaperComponent);
- clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, null);
+ clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
}
}
if (wallpaper.nextWallpaperComponent != null
@@ -746,7 +746,7 @@
if (DEBUG) {
Slog.i(TAG, "Unable to regenerate crop; resetting");
}
- clearWallpaperLocked(false, FLAG_SET_SYSTEM, UserHandle.USER_SYSTEM, null);
+ clearWallpaperLocked(false, FLAG_SYSTEM, UserHandle.USER_SYSTEM, null);
}
} else {
if (DEBUG) {
@@ -842,7 +842,7 @@
void switchUser(int userId, IRemoteCallback reply) {
synchronized (mLock) {
mCurrentUserId = userId;
- WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SET_SYSTEM);
+ WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
// Not started watching yet, in case wallpaper data was loaded for other reasons.
if (wallpaper.wallpaperObserver == null) {
wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
@@ -865,7 +865,7 @@
e = e1;
}
Slog.w(TAG, "Failure starting previous wallpaper", e);
- clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, reply);
+ clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, reply);
}
}
@@ -885,12 +885,12 @@
}
void clearWallpaperLocked(boolean defaultFailed, int which, int userId, IRemoteCallback reply) {
- if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) {
+ if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read");
}
WallpaperData wallpaper = null;
- if (which == FLAG_SET_LOCK) {
+ if (which == FLAG_LOCK) {
wallpaper = mLockWallpaperMap.get(userId);
if (wallpaper == null) {
// It's already gone; we're done.
@@ -916,7 +916,7 @@
if (wallpaper.wallpaperFile.exists()) {
wallpaper.wallpaperFile.delete();
wallpaper.cropFile.delete();
- if (which == FLAG_SET_LOCK) {
+ if (which == FLAG_LOCK) {
mLockWallpaperMap.remove(userId);
final IWallpaperManagerCallback cb = mKeyguardListener;
if (cb != null) {
@@ -1008,7 +1008,7 @@
}
synchronized (mLock) {
int userId = UserHandle.getCallingUserId();
- WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SET_SYSTEM);
+ WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException("width and height must be > 0");
}
@@ -1070,7 +1070,7 @@
}
synchronized (mLock) {
int userId = UserHandle.getCallingUserId();
- WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SET_SYSTEM);
+ WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
if (padding.left < 0 || padding.top < 0 || padding.right < 0 || padding.bottom < 0) {
throw new IllegalArgumentException("padding must be positive: " + padding);
}
@@ -1103,13 +1103,13 @@
wallpaperUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), wallpaperUserId, false, true, "getWallpaper", null);
- if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) {
+ if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read");
}
synchronized (mLock) {
final SparseArray<WallpaperData> whichSet =
- (which == FLAG_SET_LOCK) ? mLockWallpaperMap : mWallpaperMap;
+ (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
WallpaperData wallpaper = whichSet.get(wallpaperUserId);
if (wallpaper == null) {
// common case, this is the first lookup post-boot of the system or
@@ -1157,12 +1157,12 @@
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, false, true, "getWallpaperIdForUser", null);
- if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) {
+ if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
throw new IllegalArgumentException("Must specify exactly one kind of wallpaper");
}
final SparseArray<WallpaperData> map =
- (which == FLAG_SET_LOCK) ? mLockWallpaperMap : mWallpaperMap;
+ (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
synchronized (mLock) {
WallpaperData wallpaper = map.get(userId);
if (wallpaper != null) {
@@ -1186,7 +1186,7 @@
Rect cropHint, Bundle extras, int which, IWallpaperManagerCallback completion) {
checkPermission(android.Manifest.permission.SET_WALLPAPER);
- if ((which & (FLAG_SET_LOCK|FLAG_SET_SYSTEM)) == 0) {
+ if ((which & (FLAG_LOCK|FLAG_SYSTEM)) == 0) {
Slog.e(TAG, "Must specify a valid wallpaper category to set");
return null;
}
@@ -1285,6 +1285,7 @@
wallpaper.imageWallpaperPending = false;
if (bindWallpaperComponentLocked(name, false, true, wallpaper, null)) {
wallpaper.wallpaperId = makeWallpaperIdLocked();
+ notifyCallbacksLocked(wallpaper);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -1637,7 +1638,7 @@
// Combined or just-system operations use the 'system' WallpaperData
// for this use; lock-only operations use the dedicated one.
final SparseArray<WallpaperData> whichSet =
- (which == FLAG_SET_LOCK) ? mLockWallpaperMap : mWallpaperMap;
+ (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
WallpaperData wallpaper = whichSet.get(userId);
if (wallpaper == null) {
// common case, this is the first lookup post-boot of the system or
@@ -1648,7 +1649,7 @@
// yet a lock-only wallpaper set for this user, so we need to establish
// it now.
if (wallpaper == null) {
- if (which == FLAG_SET_LOCK) {
+ if (which == FLAG_LOCK) {
wallpaper = new WallpaperData(userId,
WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
mLockWallpaperMap.put(userId, wallpaper);
diff --git a/services/core/java/com/android/server/webkit/WebViewUtilityImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
similarity index 64%
rename from services/core/java/com/android/server/webkit/WebViewUtilityImpl.java
rename to services/core/java/com/android/server/webkit/SystemImpl.java
index 4dbd02d..6052a6e 100644
--- a/services/core/java/com/android/server/webkit/WebViewUtilityImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -19,15 +19,22 @@
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.content.Context;
+import android.content.pm.IPackageDeleteObserver;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
import android.content.res.XmlResourceParser;
+import android.os.Build;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings.Global;
import android.provider.Settings;
import android.util.AndroidRuntimeException;
import android.util.Log;
-import android.webkit.WebViewFactory;
import android.webkit.WebViewFactory.MissingWebViewPackageException;
+import android.webkit.WebViewFactory;
import android.webkit.WebViewProviderInfo;
import com.android.internal.util.XmlUtils;
@@ -42,8 +49,8 @@
* Default implementation for the WebView preparation Utility interface.
* @hide
*/
-public class WebViewUtilityImpl implements WebViewUtilityInterface {
- private static final String TAG = WebViewUtilityImpl.class.getSimpleName();
+public class SystemImpl implements SystemInterface {
+ private static final String TAG = SystemImpl.class.getSimpleName();
private static final String TAG_START = "webviewproviders";
private static final String TAG_WEBVIEW_PROVIDER = "webviewprovider";
private static final String TAG_PACKAGE_NAME = "packageName";
@@ -87,10 +94,10 @@
parser.getAttributeValue(null, TAG_AVAILABILITY));
boolean isFallback = "true".equals(
parser.getAttributeValue(null, TAG_FALLBACK));
- WebViewProviderInfo currentProvider =
- new WebViewProviderInfo(packageName, description, availableByDefault,
- isFallback, readSignatures(parser));
- if (currentProvider.isFallbackPackage()) {
+ WebViewProviderInfo currentProvider = new WebViewProviderInfo(
+ packageName, description, availableByDefault, isFallback,
+ readSignatures(parser));
+ if (currentProvider.isFallback) {
numFallbackPackages++;
if (numFallbackPackages > 1) {
throw new AndroidRuntimeException(
@@ -158,4 +165,67 @@
} catch (RemoteException e) {
}
}
+
+ @Override
+ public boolean isFallbackLogicEnabled() {
+ // Note that this is enabled by default (i.e. if the setting hasn't been set).
+ return Settings.Global.getInt(AppGlobals.getInitialApplication().getContentResolver(),
+ Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, 1) == 1;
+ }
+
+ @Override
+ public void enableFallbackLogic(boolean enable) {
+ Settings.Global.putInt(AppGlobals.getInitialApplication().getContentResolver(),
+ Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, enable ? 1 : 0);
+ }
+
+ @Override
+ public void uninstallAndDisablePackageForAllUsers(Context context, String packageName) {
+ context.getPackageManager().deletePackage(packageName,
+ new IPackageDeleteObserver.Stub() {
+ public void packageDeleted(String packageName, int returnCode) {
+ // Ignore returnCode since the deletion could fail, e.g. we might be trying
+ // to delete a non-updated system-package (and we should still disable the
+ // package)
+ enablePackageForAllUsers(context, packageName, false);
+ }
+ }, PackageManager.DELETE_SYSTEM_APP | PackageManager.DELETE_ALL_USERS);
+ }
+
+ @Override
+ public void enablePackageForAllUsers(Context context, String packageName, boolean enable) {
+ UserManager userManager = (UserManager)context.getSystemService(Context.USER_SERVICE);
+ for(UserInfo userInfo : userManager.getUsers()) {
+ enablePackageForUser(packageName, enable, userInfo.id);
+ }
+ }
+
+ @Override
+ public void enablePackageForUser(String packageName, boolean enable, int userId) {
+ try {
+ AppGlobals.getPackageManager().setApplicationEnabledSetting(
+ packageName,
+ enable ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT :
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0,
+ userId, null);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Tried to disable " + packageName + " for user " + userId + ": " + e);
+ }
+ }
+
+ @Override
+ public boolean systemIsDebuggable() {
+ return Build.IS_DEBUGGABLE;
+ }
+
+ @Override
+ public PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo)
+ throws NameNotFoundException {
+ PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
+ return pm.getPackageInfo(configInfo.packageName, PACKAGE_FLAGS);
+ }
+
+ // flags declaring we want extra info from the package manager for webview providers
+ private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
+ | PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUtilityInterface.java b/services/core/java/com/android/server/webkit/SystemInterface.java
similarity index 67%
rename from services/core/java/com/android/server/webkit/WebViewUtilityInterface.java
rename to services/core/java/com/android/server/webkit/SystemInterface.java
index 1919f40..b5eb0a7 100644
--- a/services/core/java/com/android/server/webkit/WebViewUtilityInterface.java
+++ b/services/core/java/com/android/server/webkit/SystemInterface.java
@@ -16,22 +16,35 @@
package com.android.server.webkit;
-import android.webkit.WebViewProviderInfo;
import android.content.Context;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.webkit.WebViewProviderInfo;
/**
- * Utility interface for the WebViewUpdateService.
+ * System interface for the WebViewUpdateService.
* This interface provides a way to test the WebView preparation mechanism - during normal use this
* interface is implemented using calls to the Android framework, but by providing an alternative
* implementation we can test the WebView preparation logic without reaching other framework code.
+ *
* @hide
*/
-public interface WebViewUtilityInterface {
+public interface SystemInterface {
public WebViewProviderInfo[] getWebViewPackages();
public int onWebViewProviderChanged(PackageInfo packageInfo);
public String getUserChosenWebViewProvider(Context context);
public void updateUserSetting(Context context, String newProviderName);
public void killPackageDependents(String packageName);
+
+ public boolean isFallbackLogicEnabled();
+ public void enableFallbackLogic(boolean enable);
+
+ public void uninstallAndDisablePackageForAllUsers(Context context, String packageName);
+ public void enablePackageForAllUsers(Context context, String packageName, boolean enable);
+ public void enablePackageForUser(String packageName, boolean enable, int userId);
+
+ public boolean systemIsDebuggable();
+ public PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo)
+ throws NameNotFoundException;
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index 50699f8..4669676 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -16,28 +16,20 @@
package com.android.server.webkit;
-import android.app.ActivityManagerNative;
-import android.app.AppGlobals;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageDeleteObserver;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
-import android.content.pm.UserInfo;
import android.os.Binder;
import android.os.PatternMatcher;
import android.os.Process;
-import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings.Global;
-import android.provider.Settings;
-import android.util.AndroidRuntimeException;
+import android.util.Base64;
import android.util.Slog;
import android.webkit.IWebViewUpdateService;
import android.webkit.WebViewFactory;
@@ -49,7 +41,6 @@
import java.io.FileDescriptor;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Iterator;
import java.util.List;
/**
@@ -72,15 +63,13 @@
// The WebView package currently in use (or the one we are preparing).
private PackageInfo mCurrentWebViewPackage = null;
- // The WebView providers that are currently available.
- private WebViewProviderInfo[] mCurrentValidWebViewPackages = null;
private BroadcastReceiver mWebViewUpdatedReceiver;
- private WebViewUtilityInterface mWebViewUtility;
+ private SystemInterface mSystemInterface;
public WebViewUpdateService(Context context) {
super(context);
- mWebViewUtility = new WebViewUtilityImpl();
+ mSystemInterface = new SystemImpl();
}
@Override
@@ -102,7 +91,7 @@
// Ensure that we only heed PACKAGE_CHANGED intents if they change an entire
// package, not just a component
if (intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED)) {
- if (!WebViewFactory.entirePackageChanged(intent)) {
+ if (!entirePackageChanged(intent)) {
return;
}
}
@@ -116,7 +105,7 @@
updateFallbackState(context, intent);
- for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) {
+ for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) {
String webviewPackage = "package:" + provider.packageName;
if (webviewPackage.equals(intent.getDataString())) {
@@ -126,7 +115,6 @@
PackageInfo newPackage = null;
synchronized(WebViewUpdateService.this) {
try {
- updateValidWebViewPackages();
newPackage = findPreferredWebViewPackage();
if (mCurrentWebViewPackage != null)
oldProviderName = mCurrentWebViewPackage.packageName;
@@ -155,7 +143,7 @@
// package that was not the previous provider then we must kill
// packages dependent on the old package ourselves. The framework
// only kills dependents of packages that are being removed.
- mWebViewUtility.killPackageDependents(oldProviderName);
+ mSystemInterface.killPackageDependents(oldProviderName);
}
return;
}
@@ -168,7 +156,7 @@
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addDataScheme("package");
// Make sure we only receive intents for WebView packages from our config file.
- for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) {
+ for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) {
filter.addDataSchemeSpecificPart(provider.packageName, PatternMatcher.PATTERN_LITERAL);
}
getContext().registerReceiver(mWebViewUpdatedReceiver, filter);
@@ -180,42 +168,34 @@
publishBinderService("webviewupdate", new BinderService(), true /*allowIsolated*/);
}
- private static boolean existsValidNonFallbackProvider(WebViewProviderInfo[] providers) {
+ private boolean existsValidNonFallbackProvider(WebViewProviderInfo[] providers) {
for (WebViewProviderInfo provider : providers) {
- if (provider.isAvailableByDefault() && provider.isEnabled()
- && provider.isValidProvider() && !provider.isFallbackPackage()) {
- return true;
+ if (provider.availableByDefault && !provider.isFallback) {
+ try {
+ PackageInfo packageInfo = mSystemInterface.getPackageInfoForProvider(provider);
+ if (isEnabledPackage(packageInfo) && isValidProvider(provider, packageInfo)) {
+ return true;
+ }
+ } catch (NameNotFoundException e) {
+ // A non-existent provider is neither valid nor enabled
+ }
}
}
return false;
}
- private static void enablePackageForUser(String packageName, boolean enable, int userId) {
- try {
- AppGlobals.getPackageManager().setApplicationEnabledSetting(
- packageName,
- enable ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT :
- PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0,
- userId, null);
- } catch (RemoteException e) {
- Slog.w(TAG, "Tried to disable " + packageName + " for user " + userId + ": " + e);
- }
- }
-
/**
* Called when a new user has been added to update the state of its fallback package.
*/
void handleNewUser(int userId) {
- if (!isFallbackLogicEnabled()) return;
+ if (!mSystemInterface.isFallbackLogicEnabled()) return;
- WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages();
+ WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
if (fallbackProvider == null) return;
- boolean existsValidNonFallbackProvider =
- existsValidNonFallbackProvider(webviewProviders);
- enablePackageForUser(fallbackProvider.packageName, !existsValidNonFallbackProvider,
- userId);
+ mSystemInterface.enablePackageForUser(fallbackProvider.packageName,
+ !existsValidNonFallbackProvider(webviewProviders), userId);
}
/**
@@ -224,9 +204,9 @@
* otherwise, enable the fallback package.
*/
void updateFallbackState(final Context context, final Intent intent) {
- if (!isFallbackLogicEnabled()) return;
+ if (!mSystemInterface.isFallbackLogicEnabled()) return;
- WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages();
+ WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
if (intent != null && (intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED)
|| intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED))) {
@@ -236,7 +216,7 @@
for (WebViewProviderInfo provider : webviewProviders) {
String webviewPackage = "package:" + provider.packageName;
if (webviewPackage.equals(intent.getDataString())) {
- if (provider.isAvailableByDefault()) {
+ if (provider.availableByDefault) {
changedPackage = provider.packageName;
}
break;
@@ -251,76 +231,44 @@
if (fallbackProvider == null) return;
boolean existsValidNonFallbackProvider = existsValidNonFallbackProvider(webviewProviders);
+ boolean isFallbackEnabled = false;
+ try {
+ isFallbackEnabled =
+ isEnabledPackage(mSystemInterface.getPackageInfoForProvider(fallbackProvider));
+ } catch (NameNotFoundException e) {
+ }
+
if (existsValidNonFallbackProvider
// During an OTA the primary user's WebView state might differ from other users', so
// ignore the state of that user during boot.
- && (fallbackProvider.isEnabled() || intent == null)) {
- // Uninstall and disable fallback package for all users.
- context.getPackageManager().deletePackage(fallbackProvider.packageName,
- new IPackageDeleteObserver.Stub() {
- public void packageDeleted(String packageName, int returnCode) {
- // Ignore returnCode since the deletion could fail, e.g. we might be trying
- // to delete a non-updated system-package (and we should still disable the
- // package)
- UserManager userManager =
- (UserManager)context.getSystemService(Context.USER_SERVICE);
- // Disable the fallback package for all users.
- for(UserInfo userInfo : userManager.getUsers()) {
- enablePackageForUser(packageName, false, userInfo.id);
- }
- }
- }, PackageManager.DELETE_SYSTEM_APP | PackageManager.DELETE_ALL_USERS);
+ && (isFallbackEnabled || intent == null)) {
+ mSystemInterface.uninstallAndDisablePackageForAllUsers(context,
+ fallbackProvider.packageName);
} else if (!existsValidNonFallbackProvider
// During an OTA the primary user's WebView state might differ from other users', so
// ignore the state of that user during boot.
- && (!fallbackProvider.isEnabled() || intent==null)) {
+ && (!isFallbackEnabled || intent==null)) {
// Enable the fallback package for all users.
- UserManager userManager =
- (UserManager)context.getSystemService(Context.USER_SERVICE);
- for(UserInfo userInfo : userManager.getUsers()) {
- enablePackageForUser(fallbackProvider.packageName, true, userInfo.id);
- }
+ mSystemInterface.enablePackageForAllUsers(context, fallbackProvider.packageName, true);
}
}
- private static boolean isFallbackLogicEnabled() {
- // Note that this is enabled by default (i.e. if the setting hasn't been set).
- return Settings.Global.getInt(AppGlobals.getInitialApplication().getContentResolver(),
- Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, 1) == 1;
- }
-
- private static void enableFallbackLogic(boolean enable) {
- Settings.Global.putInt(AppGlobals.getInitialApplication().getContentResolver(),
- Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, enable ? 1 : 0);
- }
-
/**
* Returns the only fallback provider, or null if there is none.
*/
private static WebViewProviderInfo getFallbackProvider(WebViewProviderInfo[] webviewPackages) {
for (WebViewProviderInfo provider : webviewPackages) {
- if (provider.isFallbackPackage()) {
+ if (provider.isFallback) {
return provider;
}
}
return null;
}
- private static boolean containsAvailableNonFallbackProvider(
- WebViewProviderInfo[] webviewPackages) {
- for (WebViewProviderInfo provider : webviewPackages) {
- if (provider.isAvailableByDefault() && provider.isEnabled()
- && provider.isValidProvider() && !provider.isFallbackPackage()) {
- return true;
- }
- }
- return false;
- }
-
private boolean isFallbackPackage(String packageName) {
- if (packageName == null || !isFallbackLogicEnabled()) return false;
+ if (packageName == null || !mSystemInterface.isFallbackLogicEnabled()) return false;
- WebViewProviderInfo[] webviewPackages = mWebViewUtility.getWebViewPackages();
+ WebViewProviderInfo[] webviewPackages = mSystemInterface.getWebViewPackages();
WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewPackages);
return (fallbackProvider != null
&& packageName.equals(fallbackProvider.packageName));
@@ -336,7 +284,6 @@
updateFallbackState(getContext(), null);
try {
synchronized(this) {
- updateValidWebViewPackages();
mCurrentWebViewPackage = findPreferredWebViewPackage();
onWebViewProviderChanged(mCurrentWebViewPackage);
}
@@ -357,13 +304,13 @@
PackageInfo newPackage = null;
synchronized(this) {
oldPackage = mCurrentWebViewPackage;
- mWebViewUtility.updateUserSetting(getContext(), newProviderName);
+ mSystemInterface.updateUserSetting(getContext(), newProviderName);
try {
newPackage = findPreferredWebViewPackage();
if (oldPackage != null && newPackage.packageName.equals(oldPackage.packageName)) {
// If we don't perform the user change, revert the settings change.
- mWebViewUtility.updateUserSetting(getContext(), newPackage.packageName);
+ mSystemInterface.updateUserSetting(getContext(), newPackage.packageName);
return newPackage.packageName;
}
} catch (WebViewFactory.MissingWebViewPackageException e) {
@@ -377,7 +324,7 @@
}
// Kill apps using the old provider
if (oldPackage != null) {
- mWebViewUtility.killPackageDependents(oldPackage.packageName);
+ mSystemInterface.killPackageDependents(oldPackage.packageName);
}
return newPackage.packageName;
}
@@ -391,14 +338,14 @@
mAnyWebViewInstalled = true;
if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
mCurrentWebViewPackage = newPackage;
- mWebViewUtility.updateUserSetting(getContext(), newPackage.packageName);
+ mSystemInterface.updateUserSetting(getContext(), newPackage.packageName);
// The relro creations might 'finish' (not start at all) before
// WebViewFactory.onWebViewProviderChanged which means we might not know the number
// of started creations before they finish.
mNumRelroCreationsStarted = NUMBER_OF_RELROS_UNKNOWN;
mNumRelroCreationsFinished = 0;
- mNumRelroCreationsStarted = mWebViewUtility.onWebViewProviderChanged(newPackage);
+ mNumRelroCreationsStarted = mSystemInterface.onWebViewProviderChanged(newPackage);
// If the relro creations finish before we know the number of started creations we
// will have to do any cleanup/notifying here.
checkIfRelrosDoneLocked();
@@ -408,24 +355,42 @@
}
}
- /**
- * Updates the currently valid WebView provider packages.
- * Should be used when a provider has been installed or removed.
- * @hide
- * */
- private void updateValidWebViewPackages() {
- List<WebViewProviderInfo> webViewProviders =
- new ArrayList<WebViewProviderInfo>(Arrays.asList(mWebViewUtility.getWebViewPackages()));
- Iterator<WebViewProviderInfo> it = webViewProviders.iterator();
- // remove non-valid packages
- while(it.hasNext()) {
- WebViewProviderInfo current = it.next();
- if (!current.isValidProvider())
- it.remove();
+ private ProviderAndPackageInfo[] getValidWebViewPackagesAndInfos() {
+ WebViewProviderInfo[] allProviders = mSystemInterface.getWebViewPackages();
+ List<ProviderAndPackageInfo> providers = new ArrayList<>();
+ for(int n = 0; n < allProviders.length; n++) {
+ try {
+ PackageInfo packageInfo =
+ mSystemInterface.getPackageInfoForProvider(allProviders[n]);
+ if (isValidProvider(allProviders[n], packageInfo)) {
+ providers.add(new ProviderAndPackageInfo(allProviders[n], packageInfo));
+ }
+ } catch (NameNotFoundException e) {
+ // Don't add non-existent packages
+ }
}
- synchronized(this) {
- mCurrentValidWebViewPackages =
- webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
+ return providers.toArray(new ProviderAndPackageInfo[providers.size()]);
+ }
+
+ /**
+ * Fetch only the currently valid WebView packages.
+ **/
+ private WebViewProviderInfo[] getValidWebViewPackages() {
+ ProviderAndPackageInfo[] providersAndPackageInfos = getValidWebViewPackagesAndInfos();
+ WebViewProviderInfo[] providers = new WebViewProviderInfo[providersAndPackageInfos.length];
+ for(int n = 0; n < providersAndPackageInfos.length; n++) {
+ providers[n] = providersAndPackageInfos[n].provider;
+ }
+ return providers;
+ }
+
+ private class ProviderAndPackageInfo {
+ public final WebViewProviderInfo provider;
+ public final PackageInfo packageInfo;
+
+ public ProviderAndPackageInfo(WebViewProviderInfo provider, PackageInfo packageInfo) {
+ this.provider = provider;
+ this.packageInfo = packageInfo;
}
}
@@ -437,28 +402,30 @@
* @hide
*/
private PackageInfo findPreferredWebViewPackage() {
- WebViewProviderInfo[] providers = mCurrentValidWebViewPackages;
+ ProviderAndPackageInfo[] providers = getValidWebViewPackagesAndInfos();
- String userChosenProvider = mWebViewUtility.getUserChosenWebViewProvider(getContext());
+ String userChosenProvider = mSystemInterface.getUserChosenWebViewProvider(getContext());
// If the user has chosen provider, use that
- for (WebViewProviderInfo provider : providers) {
- if (provider.packageName.equals(userChosenProvider) && provider.isEnabled()) {
- return provider.getPackageInfo();
+ for (ProviderAndPackageInfo providerAndPackage : providers) {
+ if (providerAndPackage.provider.packageName.equals(userChosenProvider)
+ && isEnabledPackage(providerAndPackage.packageInfo)) {
+ return providerAndPackage.packageInfo;
}
}
// User did not choose, or the choice failed; use the most stable provider that is
// enabled and available by default (not through user choice).
- for (WebViewProviderInfo provider : providers) {
- if (provider.isAvailableByDefault() && provider.isEnabled()) {
- return provider.getPackageInfo();
+ for (ProviderAndPackageInfo providerAndPackage : providers) {
+ if (providerAndPackage.provider.availableByDefault
+ && isEnabledPackage(providerAndPackage.packageInfo)) {
+ return providerAndPackage.packageInfo;
}
}
// Could not find any enabled package either, use the most stable provider.
- for (WebViewProviderInfo provider : providers) {
- return provider.getPackageInfo();
+ for (ProviderAndPackageInfo providerAndPackage : providers) {
+ return providerAndPackage.packageInfo;
}
mAnyWebViewInstalled = false;
@@ -466,6 +433,64 @@
"Could not find a loadable WebView package");
}
+
+ /**
+ * Returns whether this provider is valid for use as a WebView provider.
+ */
+ public boolean isValidProvider(WebViewProviderInfo configInfo,
+ PackageInfo packageInfo) {
+ if (providerHasValidSignature(configInfo, packageInfo) &&
+ WebViewFactory.getWebViewLibrary(packageInfo.applicationInfo) != null) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean providerHasValidSignature(WebViewProviderInfo provider,
+ PackageInfo packageInfo) {
+ if (mSystemInterface.systemIsDebuggable()) {
+ return true;
+ }
+ Signature[] packageSignatures;
+ // If no signature is declared, instead check whether the package is included in the
+ // system.
+ if (provider.signatures == null || provider.signatures.length == 0) {
+ return packageInfo.applicationInfo.isSystemApp();
+ }
+ packageSignatures = packageInfo.signatures;
+ if (packageSignatures.length != 1)
+ return false;
+
+ final byte[] packageSignature = packageSignatures[0].toByteArray();
+ // Return whether the package signature matches any of the valid signatures
+ for (String signature : provider.signatures) {
+ final byte[] validSignature = Base64.decode(signature, Base64.DEFAULT);
+ if (Arrays.equals(packageSignature, validSignature))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether the given package is enabled.
+ * This state can be changed by the user from Settings->Apps
+ */
+ public boolean isEnabledPackage(PackageInfo packageInfo) {
+ return packageInfo.applicationInfo.enabled;
+ }
+
+ /**
+ * Returns whether the entire package from an ACTION_PACKAGE_CHANGED intent was changed (rather
+ * than just one of its components).
+ * @hide
+ */
+ public static boolean entirePackageChanged(Intent intent) {
+ String[] componentList =
+ intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
+ return Arrays.asList(componentList).contains(
+ intent.getDataString().substring("package:".length()));
+ }
+
/**
* Returns whether WebView is ready and is not going to go through its preparation phase again
* directly.
@@ -588,19 +613,22 @@
throw new SecurityException(msg);
}
- return WebViewUpdateService.this.changeProviderAndSetting(newProvider);
- }
-
- @Override // Binder call
- public WebViewProviderInfo[] getValidWebViewPackages() {
- synchronized(WebViewUpdateService.this) {
- return mCurrentValidWebViewPackages;
+ long callingId = Binder.clearCallingIdentity();
+ try {
+ return WebViewUpdateService.this.changeProviderAndSetting(newProvider);
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
}
}
@Override // Binder call
+ public WebViewProviderInfo[] getValidWebViewPackages() {
+ return WebViewUpdateService.this.getValidWebViewPackages();
+ }
+
+ @Override // Binder call
public WebViewProviderInfo[] getAllWebViewPackages() {
- return WebViewUpdateService.this.mWebViewUtility.getWebViewPackages();
+ return WebViewUpdateService.this.mSystemInterface.getWebViewPackages();
}
@Override // Binder call
@@ -630,7 +658,7 @@
throw new SecurityException(msg);
}
- WebViewUpdateService.enableFallbackLogic(enable);
+ WebViewUpdateService.this.mSystemInterface.enableFallbackLogic(enable);
}
}
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand.java
index a9461e8..68448f3 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand.java
@@ -36,12 +36,13 @@
final PrintWriter pw = getOutPrintWriter();
try {
- // TODO(gsennton) add command for changing WebView provider
switch(cmd) {
case "enable-redundant-packages":
return enableFallbackLogic(false);
case "disable-redundant-packages":
return enableFallbackLogic(true);
+ case "set-webview-implementation":
+ return setWebViewImplementation();
default:
return handleDefaultCommands(cmd);
}
@@ -58,6 +59,21 @@
return 0;
}
+ private int setWebViewImplementation() throws RemoteException {
+ final PrintWriter pw = getOutPrintWriter();
+ String shellChosenPackage = getNextArg();
+ String newPackage = mInterface.changeProviderAndSetting(shellChosenPackage);
+ if (shellChosenPackage.equals(newPackage)) {
+ pw.println("Success");
+ return 0;
+ } else {
+ pw.println(String.format(
+ "Failed to switch to %s, the WebView implementation is now provided by %s.",
+ shellChosenPackage, newPackage));
+ return 1;
+ }
+ }
+
@Override
public void onHelp() {
PrintWriter pw = getOutPrintWriter();
@@ -72,6 +88,8 @@
pw.println(" disable-redundant-packages");
pw.println(" Disallow installing and enabling fallback packages when a more-preferred");
pw.println(" package is available.");
+ pw.println(" set-webview-implementation PACKAGE");
+ pw.println(" Set the WebView implementation to the specified package.");
pw.println();
}
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index b501398..bae628a 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -39,6 +39,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
@@ -1213,6 +1214,8 @@
window.type = windowState.mAttrs.type;
window.layer = windowState.mLayer;
window.token = windowState.mClient.asBinder();
+ window.title = windowState.mAttrs.getTitle();
+ window.accessibilityIdOfAnchor = windowState.mAttrs.accessibilityIdOfAnchor;
WindowState attachedWindow = windowState.mAttachedWindow;
if (attachedWindow != null) {
@@ -1285,6 +1288,12 @@
&& !oldWindow.childTokens.equals(newWindow.childTokens)) {
return true;
}
+ if (!TextUtils.equals(oldWindow.title, newWindow.title)) {
+ return true;
+ }
+ if (oldWindow.accessibilityIdOfAnchor != newWindow.accessibilityIdOfAnchor) {
+ return true;
+ }
return false;
}
diff --git a/services/core/java/com/android/server/wm/DimLayerController.java b/services/core/java/com/android/server/wm/DimLayerController.java
index 97d0ae0..3ec02b9 100644
--- a/services/core/java/com/android/server/wm/DimLayerController.java
+++ b/services/core/java/com/android/server/wm/DimLayerController.java
@@ -183,7 +183,12 @@
for (int i = mState.size() - 1; i >= 0; i--) {
DimLayer.DimLayerUser user = mState.keyAt(i);
- if (user.isFullscreen()) {
+ DimLayerState state = mState.valueAt(i);
+ // We have to check that we are acutally the shared fullscreen layer
+ // for this path. If we began as non fullscreen and became fullscreen
+ // (e.g. Docked stack closing), then we may not be the shared layer
+ // and we have to make sure we always animate the layer.
+ if (user.isFullscreen() && state.dimLayer == mSharedFullScreenDimLayer) {
fullScreen = i;
if (mState.valueAt(i).continueDimming) {
fullScreenAndDimming = i;
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 68ea4df..6f7e64f 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -243,6 +243,9 @@
}
}
mDockedStackListeners.finishBroadcast();
+ if (!exists) {
+ setMinimizedDockedStack(false);
+ }
}
void notifyDockedStackMinimizedChanged(boolean minimizedDock, long animDuration) {
@@ -263,6 +266,7 @@
notifyDockedDividerVisibilityChanged(wasVisible());
notifyDockedStackExistsChanged(
mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID) != null);
+ notifyDockedStackMinimizedChanged(mMinimizedDock, 0 /* animDuration */);
}
void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
@@ -338,12 +342,13 @@
* @param animate Whether to animate the change.
*/
private void setMinimizedDockedStack(boolean minimizedDock, boolean animate) {
- if (minimizedDock == mMinimizedDock
+ final boolean wasMinimized = mMinimizedDock;
+ mMinimizedDock = minimizedDock;
+ if (minimizedDock == wasMinimized
|| mDisplayContent.getDockedStackVisibleForUserLocked() == null) {
return;
}
- mMinimizedDock = minimizedDock;
mAnimatingForIme = false;
if (minimizedDock) {
if (animate) {
@@ -369,13 +374,13 @@
private void setMinimizedDockedStack(boolean minimized) {
final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
+ notifyDockedStackMinimizedChanged(minimized, 0);
if (stack == null) {
return;
}
if (stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f)) {
mService.mWindowPlacerLocked.performSurfacePlacement();
}
- notifyDockedStackMinimizedChanged(minimized, 0);
}
private boolean isAnimationMaximizing() {
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index cf27b97..aace5e7 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -589,7 +589,7 @@
void overridePointerIconLw(int touchSource) {
mTouchSource = touchSource;
if (isFromSource(InputDevice.SOURCE_MOUSE)) {
- InputManager.getInstance().setPointerIconShape(PointerIcon.STYLE_GRAB);
+ InputManager.getInstance().setPointerIconShape(PointerIcon.STYLE_GRABBING);
}
}
}
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 0581a16..24783bc 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -16,38 +16,33 @@
package com.android.server.wm;
-import android.os.Looper;
import android.os.Process;
import android.view.Display;
import android.view.InputChannel;
-import android.view.InputEventReceiver;
import android.view.WindowManager;
-import android.view.WindowManagerPolicy;
-
import com.android.server.input.InputApplicationHandle;
import com.android.server.input.InputWindowHandle;
-public final class InputConsumerImpl implements WindowManagerPolicy.InputConsumer {
+class InputConsumerImpl {
final WindowManagerService mService;
final InputChannel mServerChannel, mClientChannel;
final InputApplicationHandle mApplicationHandle;
final InputWindowHandle mWindowHandle;
- final InputEventReceiver mInputEventReceiver;
- final int mWindowLayer;
- public InputConsumerImpl(WindowManagerService service, Looper looper,
- InputEventReceiver.Factory inputEventReceiverFactory) {
- String name = "input consumer";
+ InputConsumerImpl(WindowManagerService service, String name, InputChannel inputChannel) {
mService = service;
InputChannel[] channels = InputChannel.openInputChannelPair(name);
mServerChannel = channels[0];
- mClientChannel = channels[1];
+ if (inputChannel != null) {
+ channels[1].transferTo(inputChannel);
+ channels[1].dispose();
+ mClientChannel = inputChannel;
+ } else {
+ mClientChannel = channels[1];
+ }
mService.mInputManager.registerInputChannel(mServerChannel, null);
- mInputEventReceiver = inputEventReceiverFactory.createInputEventReceiver(
- mClientChannel, looper);
-
mApplicationHandle = new InputApplicationHandle(null);
mApplicationHandle.name = name;
mApplicationHandle.dispatchingTimeoutNanos =
@@ -57,8 +52,7 @@
mWindowHandle.name = name;
mWindowHandle.inputChannel = mServerChannel;
mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
- mWindowLayer = getLayerLw(mWindowHandle.layoutParamsType);
- mWindowHandle.layer = mWindowLayer;
+ mWindowHandle.layer = getLayerLw(mWindowHandle.layoutParamsType);
mWindowHandle.layoutParamsFlags = 0;
mWindowHandle.dispatchingTimeoutNanos =
WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
@@ -81,21 +75,15 @@
mWindowHandle.frameBottom = dh;
}
- @Override
- public void dismiss() {
- synchronized (mService.mWindowMap) {
- if (mService.removeInputConsumer()) {
- mInputEventReceiver.dispose();
- mService.mInputManager.unregisterInputChannel(mServerChannel);
- mClientChannel.dispose();
- mServerChannel.dispose();
- }
- }
- }
-
private int getLayerLw(int windowType) {
return mService.mPolicy.windowTypeToLayerLw(windowType)
* WindowManagerService.TYPE_LAYER_MULTIPLIER
+ WindowManagerService.TYPE_LAYER_OFFSET;
}
+
+ void disposeChannelsLw() {
+ mService.mInputManager.unregisterInputChannel(mServerChannel);
+ mClientChannel.dispose();
+ mServerChannel.dispose();
+ }
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index b702180..eea0e73 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -282,6 +282,8 @@
boolean addInputConsumerHandle = mService.mInputConsumer != null;
+ boolean addWallpaperInputConsumerHandle = mService.mWallpaperInputConsumer != null;
+
// Add all windows on the default display.
final int numDisplays = mService.mDisplayContents.size();
final WallpaperController wallpaperController = mService.mWallpaperControllerLocked;
@@ -302,6 +304,14 @@
addInputConsumerHandle = false;
}
+ if (addWallpaperInputConsumerHandle) {
+ if (child.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER) {
+ // Add the wallpaper input consumer above the first wallpaper window.
+ addInputWindowHandleLw(mService.mWallpaperInputConsumer.mWindowHandle);
+ addWallpaperInputConsumerHandle = false;
+ }
+ }
+
final int flags = child.mAttrs.flags;
final int privateFlags = child.mAttrs.privateFlags;
final int type = child.mAttrs.type;
@@ -329,6 +339,11 @@
}
}
+ if (addWallpaperInputConsumerHandle) {
+ // No wallpaper found, add the wallpaper input consumer at the end.
+ addInputWindowHandleLw(mService.mWallpaperInputConsumer.mWindowHandle);
+ }
+
// Send windows to native code.
mService.mInputManager.setInputWindows(mInputWindowHandles);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 1f03c04..eea0ca0 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -425,7 +425,7 @@
if (mFullscreen
|| !StackId.isTaskResizeableByDockedStack(mStack.mStackId)
|| displayContent == null
- || displayContent.getDockedStackLocked() != null) {
+ || displayContent.getDockedStackVisibleForUserLocked() != null) {
return true;
}
return false;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 0bf7102..0225c9b 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -128,6 +128,10 @@
// in which case a second window animation would cause jitter.
private boolean mFreezeMovementAnimations = false;
+ // Temporary storage for the new bounds that should be used after the configuration change.
+ // Will be cleared once the client retrieves the new bounds via getBoundsForNewConfiguration().
+ private final Rect mBoundsAfterRotation = new Rect();
+
TaskStack(WindowManagerService service, int stackId) {
mService = service;
mStackId = stackId;
@@ -343,28 +347,28 @@
setBounds(mTmpRect2);
} else {
mLastUpdateDisplayInfoRotation = newRotation;
- updateBoundsAfterRotation();
+ updateBoundsAfterRotation(true);
}
}
- void onConfigurationChanged() {
+ boolean onConfigurationChanged() {
mLastConfigChangedRotation = getDisplayInfo().rotation;
- updateBoundsAfterRotation();
+ return updateBoundsAfterRotation(false);
}
- void updateBoundsAfterRotation() {
+ boolean updateBoundsAfterRotation(boolean scheduleResize) {
if (mLastConfigChangedRotation != mLastUpdateDisplayInfoRotation) {
// We wait for the rotation values after configuration change and display info. update
// to be equal before updating the bounds due to rotation change otherwise things might
// get out of alignment...
- return;
+ return false;
}
final int newRotation = getDisplayInfo().rotation;
if (mRotation == newRotation) {
// Nothing to do here if the rotation didn't change
- return;
+ return false;
}
mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
@@ -373,11 +377,22 @@
snapDockedStackAfterRotation(mTmpRect2);
}
- // Post message to inform activity manager of the bounds change simulating
- // a one-way call. We do this to prevent a deadlock between window manager
- // lock and activity manager lock been held.
- mService.mH.obtainMessage(
- RESIZE_STACK, mStackId, 0 /*allowResizeInDockedMode*/, mTmpRect2).sendToTarget();
+ if (scheduleResize) {
+ // Post message to inform activity manager of the bounds change simulating
+ // a one-way call. We do this to prevent a deadlock between window manager
+ // lock and activity manager lock been held.
+ mService.mH.obtainMessage(RESIZE_STACK, mStackId,
+ 0 /*allowResizeInDockedMode*/, mTmpRect2).sendToTarget();
+ } else {
+ mBoundsAfterRotation.set(mTmpRect2);
+ }
+
+ return true;
+ }
+
+ void getBoundsForNewConfiguration(Rect outBounds) {
+ outBounds.set(mBoundsAfterRotation);
+ mBoundsAfterRotation.setEmpty();
}
/**
@@ -869,6 +884,10 @@
}
}
+ boolean isAdjustedForMinimizedDock() {
+ return mMinimizeAmount != 0f;
+ }
+
private boolean adjustForIME(final WindowState imeWin) {
final int dockedSide = getDockSide();
final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
@@ -938,9 +957,11 @@
(int) (minimizeAmount * topInset + (1 - minimizeAmount) * mBounds.bottom);
} else if (dockSide == DOCKED_LEFT) {
mTmpAdjustedBounds.set(mBounds);
+ final int width = mBounds.width();
mTmpAdjustedBounds.right =
(int) (minimizeAmount * mDockedStackMinimizeThickness
+ (1 - minimizeAmount) * mBounds.right);
+ mTmpAdjustedBounds.left = mTmpAdjustedBounds.right - width;
} else if (dockSide == DOCKED_RIGHT) {
mTmpAdjustedBounds.set(mBounds);
mTmpAdjustedBounds.left =
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
index f76f03f..1d64c82 100644
--- a/services/core/java/com/android/server/wm/WindowLayersController.java
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -191,17 +191,13 @@
}
private void adjustSpecialWindows() {
- int layer = mHighestApplicationLayer + 1;
+ int layer = mHighestApplicationLayer + WINDOW_LAYER_MULTIPLIER;
// For pinned and docked stack window, we want to make them above other windows also when
// these windows are animating.
while (!mDockedWindows.isEmpty()) {
layer = assignAndIncreaseLayerIfNeeded(mDockedWindows.remove(), layer);
}
- // Leave some space here so the dim layer while dismissing docked/fullscreen stack has space
- // below the divider but above the app windows. It needs to be below the divider in because
- // the divider sometimes overlaps the app windows.
- layer++;
layer = assignAndIncreaseLayerIfNeeded(mDockDivider, layer);
// We know that we will be animating a relaunching window in the near future, which will
// receive a z-order increase. We want the replaced window to immediately receive the same
@@ -218,11 +214,12 @@
private int assignAndIncreaseLayerIfNeeded(WindowState win, int layer) {
if (win != null) {
assignAnimLayer(win, layer);
- layer++;
+ // Make sure we leave space inbetween normal windows for dims and such.
+ layer += WINDOW_LAYER_MULTIPLIER;
}
return layer;
}
-
+
private void assignAnimLayer(WindowState w, int layer) {
w.mLayer = layer;
w.mWinAnimator.mAnimLayer = w.mLayer + w.getAnimLayerAdjustment() +
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 97c4c42..e4630b4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -125,6 +125,7 @@
import com.android.internal.app.IAssistScreenshotReceiver;
import com.android.internal.os.IResultReceiver;
import com.android.internal.policy.IShortcutService;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
@@ -407,6 +408,11 @@
InputConsumerImpl mInputConsumer;
/**
+ * The input consumer added to the window manager before all wallpaper windows.
+ */
+ InputConsumerImpl mWallpaperInputConsumer;
+
+ /**
* Windows that are being resized. Used so we can tell the client about
* the resize after closing the transaction in which we resized the
* underlying surface.
@@ -510,6 +516,8 @@
private final SparseIntArray mTmpTaskIds = new SparseIntArray();
+ private final ArrayList<Integer> mChangedStackList = new ArrayList();
+
boolean mForceResizableTasks = false;
int getDragLayerLocked() {
@@ -3393,7 +3401,8 @@
}
}
- if (isStackVisibleLocked(DOCKED_STACK_ID)
+ if ((isStackVisibleLocked(DOCKED_STACK_ID)
+ && !mStackIdToStack.get(DOCKED_STACK_ID).isAdjustedForMinimizedDock())
|| isStackVisibleLocked(FREEFORM_WORKSPACE_STACK_ID)) {
// We don't let app affect the system orientation when in freeform or docked mode since
// they don't occupy the entire display and their request can conflict with other apps.
@@ -3575,7 +3584,7 @@
}
@Override
- public void setNewConfiguration(Configuration config) {
+ public int[] setNewConfiguration(Configuration config) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"setNewConfiguration()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3587,16 +3596,30 @@
mWaitingForConfig = false;
mLastFinishedFreezeSource = "new-config";
}
- onConfigurationChanged();
- mWindowPlacerLocked.performSurfacePlacement();
+ return onConfigurationChanged();
}
}
- private void onConfigurationChanged() {
+ @Override
+ public Rect getBoundsForNewConfiguration(int stackId) {
+ synchronized(mWindowMap) {
+ final TaskStack stack = mStackIdToStack.get(stackId);
+ final Rect outBounds = new Rect();
+ stack.getBoundsForNewConfiguration(outBounds);
+ return outBounds;
+ }
+ }
+
+ private int[] onConfigurationChanged() {
+ mChangedStackList.clear();
for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; stackNdx--) {
final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
- stack.onConfigurationChanged();
+ if (stack.onConfigurationChanged()) {
+ mChangedStackList.add(stack.mStackId);
+ }
}
+ return mChangedStackList.isEmpty() ?
+ null : ArrayUtils.convertToIntArray(mChangedStackList);
}
@Override
@@ -4112,6 +4135,14 @@
for (int i = 0; i < windowsCount; i++) {
WindowState win = wtoken.allAppWindows.get(i);
if (win == wtoken.startingWindow) {
+ // Starting window that's exiting will be removed when the animation
+ // finishes. Mark all relevant flags for that finishExit will proceed
+ // all the way to actually remove it.
+ if (!visible && win.isVisibleNow() && wtoken.mAppAnimator.isAnimating()) {
+ win.mAnimatingExit = true;
+ win.mRemoveOnExit = true;
+ win.mWindowRemovalAllowed = true;
+ }
continue;
}
@@ -4261,9 +4292,13 @@
wtoken.appDied = false;
wtoken.removeAllWindows();
} else if (visible) {
- mOpeningApps.add(wtoken);
+ if (!mAppTransition.isTransitionSet() && mAppTransition.isReady()) {
+ // Add the app mOpeningApps if transition is unset but ready. This means
+ // we're doing a screen freeze, and the unfreeze will wait for all opening
+ // apps to be ready.
+ mOpeningApps.add(wtoken);
+ }
wtoken.startingMoved = false;
-
// If the token is currently hidden (should be the common case), or has been
// stopped, then we need to set up to wait for its windows to be ready.
if (wtoken.hidden || wtoken.mAppStopped) {
@@ -4307,6 +4342,7 @@
}
wtoken.inPendingTransaction = true;
if (visible) {
+ mOpeningApps.add(wtoken);
wtoken.mEnteringAnimation = true;
} else {
mClosingApps.add(wtoken);
@@ -6063,7 +6099,7 @@
int bottom = wf.bottom - cr.bottom;
frame.union(left, top, right, bottom);
ws.getVisibleBounds(stackBounds);
- if (!frame.intersect(stackBounds)) {
+ if (!Rect.intersects(frame, stackBounds)) {
// Set frame empty if there's no intersection.
frame.setEmpty();
}
@@ -9624,13 +9660,37 @@
}
}
+ private static final class HideNavInputConsumer extends InputConsumerImpl
+ implements WindowManagerPolicy.InputConsumer {
+ private final InputEventReceiver mInputEventReceiver;
+
+ HideNavInputConsumer(WindowManagerService service, Looper looper,
+ InputEventReceiver.Factory inputEventReceiverFactory) {
+ super(service, "input consumer", null);
+ mInputEventReceiver = inputEventReceiverFactory.createInputEventReceiver(
+ mClientChannel, looper);
+ }
+
+ @Override
+ public void dismiss() {
+ if (mService.removeInputConsumer()) {
+ synchronized (mService.mWindowMap) {
+ mInputEventReceiver.dispose();
+ disposeChannelsLw();
+ }
+ }
+ }
+ }
+
@Override
- public InputConsumerImpl addInputConsumer(Looper looper,
+ public WindowManagerPolicy.InputConsumer addInputConsumer(Looper looper,
InputEventReceiver.Factory inputEventReceiverFactory) {
synchronized (mWindowMap) {
- mInputConsumer = new InputConsumerImpl(this, looper, inputEventReceiverFactory);
+ HideNavInputConsumer inputConsumerImpl = new HideNavInputConsumer(
+ this, looper, inputEventReceiverFactory);
+ mInputConsumer = inputConsumerImpl;
mInputMonitor.updateInputWindowsLw(true);
- return mInputConsumer;
+ return inputConsumerImpl;
}
}
@@ -9645,6 +9705,24 @@
}
}
+ public void createWallpaperInputConsumer(InputChannel inputChannel) {
+ synchronized (mWindowMap) {
+ mWallpaperInputConsumer = new InputConsumerImpl(this, "wallpaper input", inputChannel);
+ mWallpaperInputConsumer.mWindowHandle.hasWallpaper = true;
+ mInputMonitor.updateInputWindowsLw(true);
+ }
+ }
+
+ public void removeWallpaperInputConsumer() {
+ synchronized (mWindowMap) {
+ if (mWallpaperInputConsumer != null) {
+ mWallpaperInputConsumer.disposeChannelsLw();
+ mWallpaperInputConsumer = null;
+ mInputMonitor.updateInputWindowsLw(true);
+ }
+ }
+ }
+
@Override
public boolean hasNavigationBar() {
return mPolicy.hasNavigationBar();
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 57ead8b..c62292d 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -670,10 +670,18 @@
mContainingFrame.bottom = mContainingFrame.top + frozen.height();
}
final WindowState imeWin = mService.mInputMethodWindow;
- if (imeWin != null && imeWin.isVisibleNow() && mService.mInputMethodTarget == this
- && mContainingFrame.bottom > cf.bottom) {
- // IME is up and obscuring this window. Adjust the window position so it is visible.
- mContainingFrame.top -= mContainingFrame.bottom - cf.bottom;
+ // IME is up and obscuring this window. Adjust the window position so it is visible.
+ if (imeWin != null && imeWin.isVisibleNow() && mService.mInputMethodTarget == this) {
+ if (windowsAreFloating && mContainingFrame.bottom > cf.bottom) {
+ // In freeform we want to move the top up directly.
+ // TODO: Investigate why this is cf not pf.
+ mContainingFrame.top -= mContainingFrame.bottom - cf.bottom;
+ } else if (mContainingFrame.bottom > pf.bottom) {
+ // But in docked we want to behave like fullscreen
+ // and behave as if the task were given smaller bounds
+ // for the purposes of layout.
+ mContainingFrame.bottom = pf.bottom;
+ }
}
if (windowsAreFloating) {
@@ -799,26 +807,31 @@
mContentInsets.setEmpty();
mVisibleInsets.setEmpty();
} else {
- // Using mContentInsets as a temp rect. It is safe because we're setting it below.
- getDisplayContent().getLogicalDisplayRect(mContentInsets);
+ getDisplayContent().getLogicalDisplayRect(mTmpRect);
// Override right and/or bottom insets in case if the frame doesn't fit the screen in
// non-fullscreen mode.
- boolean overrideRightInset = !fullscreenTask && mFrame.right > mContentInsets.right;
- boolean overrideBottomInset = !fullscreenTask && mFrame.bottom > mContentInsets.bottom;
+ boolean overrideRightInset = !fullscreenTask && mFrame.right > mTmpRect.right;
+ boolean overrideBottomInset = !fullscreenTask && mFrame.bottom > mTmpRect.bottom;
mContentInsets.set(mContentFrame.left - frame.left,
mContentFrame.top - frame.top,
- overrideRightInset ? 0 : frame.right - mContentFrame.right,
- overrideBottomInset ? 0 : frame.bottom - mContentFrame.bottom);
+ overrideRightInset ? mTmpRect.right - mContentFrame.right
+ : frame.right - mContentFrame.right,
+ overrideBottomInset ? mTmpRect.bottom - mContentFrame.bottom
+ : frame.bottom - mContentFrame.bottom);
mVisibleInsets.set(mVisibleFrame.left - frame.left,
mVisibleFrame.top - frame.top,
- overrideRightInset ? 0 : frame.right - mVisibleFrame.right,
- overrideBottomInset ? 0 : frame.bottom - mVisibleFrame.bottom);
+ overrideRightInset ? mTmpRect.right - mVisibleFrame.right
+ : frame.right - mVisibleFrame.right,
+ overrideBottomInset ? mTmpRect.bottom - mVisibleFrame.bottom
+ : frame.bottom - mVisibleFrame.bottom);
mStableInsets.set(Math.max(mStableFrame.left - frame.left, 0),
Math.max(mStableFrame.top - frame.top, 0),
- overrideRightInset ? 0 : Math.max(frame.right - mStableFrame.right, 0),
- overrideBottomInset ? 0 : Math.max(frame.bottom - mStableFrame.bottom, 0));
+ overrideRightInset ? Math.max(mTmpRect.right - mStableFrame.right, 0)
+ : Math.max(frame.right - mStableFrame.right, 0),
+ overrideBottomInset ? Math.max(mTmpRect.bottom - mStableFrame.bottom, 0)
+ : Math.max(frame.bottom - mStableFrame.bottom, 0));
}
if (!mInsetFrame.isEmpty()) {
@@ -1878,6 +1891,11 @@
}
private boolean shouldSaveSurface() {
+ if (mWinAnimator.mSurfaceController == null) {
+ // Don't bother if the surface controller is gone for any reason.
+ return false;
+ }
+
if ((mAttrs.flags & FLAG_SECURE) != 0) {
// We don't save secure surfaces since their content shouldn't be shown while the app
// isn't on screen and content might leak through during the transition animation with
@@ -1951,10 +1969,18 @@
return;
}
mSurfaceSaved = false;
- setHasSurface(true);
- mWinAnimator.mDrawState = WindowStateAnimator.READY_TO_SHOW;
- if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
- Slog.v(TAG, "Restoring saved surface: " + this);
+ if (mWinAnimator.mSurfaceController != null) {
+ setHasSurface(true);
+ mWinAnimator.mDrawState = WindowStateAnimator.READY_TO_SHOW;
+
+ if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
+ Slog.v(TAG, "Restoring saved surface: " + this);
+ }
+ } else {
+ // mSurfaceController shouldn't be null if mSurfaceSaved was still true at
+ // this point. Even if we destroyed the saved surface because of rotation
+ // or resize, mSurfaceSaved flag should have been cleared. So this is a wtf.
+ Slog.wtf(TAG, "Failed to restore saved surface: surface gone! " + this);
}
}
@@ -2572,7 +2598,7 @@
y = mAttrs.y;
}
- if (nonFullscreenTask) {
+ if (nonFullscreenTask && !layoutInParentFrame()) {
// Make sure window fits in containing frame since it is in a non-fullscreen task as
// required by {@link Gravity#apply} call.
w = Math.min(w, pw);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 1e103f0..8fd8bc0 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -967,13 +967,15 @@
if (appTransformation != null) {
tmpMatrix.postConcat(appTransformation.getMatrix());
}
+
+ // The translation that applies the position of the window needs to be applied at the
+ // end in case that other translations include scaling. Otherwise the scaling will
+ // affect this translation. But it needs to be set before the screen rotation animation
+ // so the pivot point is at the center of the screen for all windows.
+ tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
if (screenAnimation) {
tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
}
- // The translation that applies the position of the window needs to be applied at the
- // end in case that other translations include scaling. Otherwise the scaling will
- // affect this translation.
- tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
//TODO (multidisplay): Magnification is supported only for the default display.
if (mService.mAccessibilityController != null && displayId == DEFAULT_DISPLAY) {
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 3e5ddbc..eda2f39 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -860,6 +860,10 @@
mService.mInputConsumer.layout(dw, dh);
}
+ if (mService.mWallpaperInputConsumer != null) {
+ mService.mWallpaperInputConsumer.layout(dw, dh);
+ }
+
final int N = windows.size();
int i;
diff --git a/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
index ec5e8c9..14d50ce 100644
--- a/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
+++ b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
@@ -36,7 +36,8 @@
enum {
TEMPERATURE_CURRENT = 0,
TEMPERATURE_THROTTLING = 1,
- TEMPERATURE_SHUTDOWN = 2
+ TEMPERATURE_SHUTDOWN = 2,
+ TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3
};
static struct {
@@ -127,6 +128,13 @@
values[length++] = list[i].shutdown_threshold;
}
break;
+ case TEMPERATURE_THROTTLING_BELOW_VR_MIN:
+ if (list[i].vr_throttling_threshold == UNKNOWN_TEMPERATURE) {
+ values[length++] = gUndefinedTemperature;
+ } else {
+ values[length++] = list[i].vr_throttling_threshold;
+ }
+ break;
}
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2248073..0d4887d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -136,6 +136,7 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
+import com.android.internal.util.ParcelableString;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.internal.widget.LockPatternUtils;
@@ -184,12 +185,16 @@
private static final String DEVICE_POLICIES_XML = "device_policies.xml";
+ private static final String TAG_ACCEPTED_CA_CERTIFICATES = "accepted-ca-certificate";
+
private static final String TAG_LOCK_TASK_COMPONENTS = "lock-task-component";
private static final String TAG_STATUS_BAR = "statusbar";
private static final String ATTR_DISABLED = "disabled";
+ private static final String ATTR_NAME = "name";
+
private static final String DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML =
"do-not-ask-credentials-on-boot";
@@ -420,6 +425,8 @@
final ArrayList<ActiveAdmin> mAdminList = new ArrayList<>();
final ArrayList<ComponentName> mRemovingAdmins = new ArrayList<>();
+ final ArraySet<String> mAcceptedCaCertificates = new ArraySet<>();
+
// This is the list of component allowed to start lock task mode.
List<String> mLockTaskPackages = new ArrayList<>();
@@ -483,7 +490,8 @@
}
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
|| KeyChain.ACTION_STORAGE_CHANGED.equals(action)) {
- new MonitoringCertNotificationTask().execute(intent);
+ int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_ALL);
+ new MonitoringCertNotificationTask().execute(userId);
}
if (Intent.ACTION_USER_ADDED.equals(action)) {
disableSecurityLoggingIfNotCompliant();
@@ -1480,6 +1488,12 @@
return "/data/system/";
}
+ void registerContentObserver(Uri uri, boolean notifyForDescendents,
+ ContentObserver observer, int userHandle) {
+ mContext.getContentResolver().registerContentObserver(uri, notifyForDescendents,
+ observer, userHandle);
+ }
+
int settingsSecureGetIntForUser(String name, int def, int userHandle) {
return Settings.Secure.getIntForUser(mContext.getContentResolver(),
name, def, userHandle);
@@ -2215,6 +2229,12 @@
out.endTag(null, "active-password");
}
+ for (int i = 0; i < policy.mAcceptedCaCertificates.size(); i++) {
+ out.startTag(null, TAG_ACCEPTED_CA_CERTIFICATES);
+ out.attribute(null, ATTR_NAME, policy.mAcceptedCaCertificates.valueAt(i));
+ out.endTag(null, TAG_ACCEPTED_CA_CERTIFICATES);
+ }
+
for (int i=0; i<policy.mLockTaskPackages.size(); i++) {
String component = policy.mLockTaskPackages.get(i);
out.startTag(null, TAG_LOCK_TASK_COMPONENTS);
@@ -2381,6 +2401,8 @@
parser.getAttributeValue(null, "symbols"));
policy.mActivePasswordNonLetter = Integer.parseInt(
parser.getAttributeValue(null, "nonletter"));
+ } else if (TAG_ACCEPTED_CA_CERTIFICATES.equals(tag)) {
+ policy.mAcceptedCaCertificates.add(parser.getAttributeValue(null, ATTR_NAME));
} else if (TAG_LOCK_TASK_COMPONENTS.equals(tag)) {
policy.mLockTaskPackages.add(parser.getAttributeValue(null, "name"));
} else if (TAG_STATUS_BAR.equals(tag)) {
@@ -2536,7 +2558,7 @@
onStartUser(UserHandle.USER_SYSTEM);
// Register an observer for watching for user setup complete.
- new SetupContentObserver(mHandler).register(mContext.getContentResolver());
+ new SetupContentObserver(mHandler).register();
// Initialize the user setup state, to handle the upgrade case.
updateUserSetupComplete();
@@ -2632,17 +2654,17 @@
}
}
- private class MonitoringCertNotificationTask extends AsyncTask<Intent, Void, Void> {
+ private class MonitoringCertNotificationTask extends AsyncTask<Integer, Void, Void> {
@Override
- protected Void doInBackground(Intent... params) {
- int userHandle = params[0].getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_ALL);
+ protected Void doInBackground(Integer... params) {
+ int userHandle = params[0];
if (userHandle == UserHandle.USER_ALL) {
for (UserInfo userInfo : mUserManager.getUsers()) {
manageNotification(userInfo.getUserHandle());
}
} else {
- manageNotification(new UserHandle(userHandle));
+ manageNotification(UserHandle.of(userHandle));
}
return null;
}
@@ -2652,25 +2674,27 @@
return;
}
- // Call out to KeyChain to check for user-added CAs
- boolean hasCert = false;
+ // Call out to KeyChain to check for CAs which are waiting for approval.
+ final List<String> pendingCertificates;
try {
- KeyChainConnection kcs = KeyChain.bindAsUser(mContext, userHandle);
- try {
- if (!kcs.getService().getUserCaAliases().getList().isEmpty()) {
- hasCert = true;
- }
- } catch (RemoteException e) {
- Log.e(LOG_TAG, "Could not connect to KeyChain service", e);
- } finally {
- kcs.close();
- }
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- } catch (RuntimeException | AssertionError e) {
- Log.e(LOG_TAG, "Could not connect to KeyChain service", e);
+ pendingCertificates = getInstalledCaCertificates(userHandle);
+ } catch (RemoteException | RuntimeException e) {
+ Log.e(LOG_TAG, "Could not retrieve certificates from KeyChain service", e);
+ return;
}
- if (!hasCert) {
+
+ synchronized (DevicePolicyManagerService.this) {
+ final DevicePolicyData policy = getUserData(userHandle.getIdentifier());
+
+ // Remove deleted certificates. Flush xml if necessary.
+ if (policy.mAcceptedCaCertificates.retainAll(pendingCertificates)) {
+ saveSettingsLocked(userHandle.getIdentifier());
+ }
+ // Trim to approved certificates.
+ pendingCertificates.removeAll(policy.mAcceptedCaCertificates);
+ }
+
+ if (pendingCertificates.isEmpty()) {
mInjector.getNotificationManager().cancelAsUser(
null, MONITORING_CERT_NOTIFICATION_ID, userHandle);
return;
@@ -2701,7 +2725,8 @@
final Context userContext;
try {
- userContext = mContext.createPackageContextAsUser("android", 0, userHandle);
+ final String packageName = mContext.getPackageName();
+ userContext = mContext.createPackageContextAsUser(packageName, 0, userHandle);
} catch (PackageManager.NameNotFoundException e) {
Log.e(LOG_TAG, "Create context as " + userHandle + " failed", e);
return;
@@ -2720,6 +2745,29 @@
mInjector.getNotificationManager().notifyAsUser(
null, MONITORING_CERT_NOTIFICATION_ID, noti, userHandle);
}
+
+ private List<String> getInstalledCaCertificates(UserHandle userHandle)
+ throws RemoteException, RuntimeException {
+ KeyChainConnection conn = null;
+ try {
+ conn = KeyChain.bindAsUser(mContext, userHandle);
+ List<ParcelableString> aliases = conn.getService().getUserCaAliases().getList();
+ List<String> result = new ArrayList<>(aliases.size());
+ for (int i = 0; i < aliases.size(); i++) {
+ result.add(aliases.get(i).string);
+ }
+ return result;
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return null;
+ } catch (AssertionError e) {
+ throw new RuntimeException(e);
+ } finally {
+ if (conn != null) {
+ conn.close();
+ }
+ }
+ }
}
/**
@@ -2757,6 +2805,10 @@
&& getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
throw new IllegalArgumentException("Admin is already added");
}
+ if (policy.mRemovingAdmins.contains(adminReceiver)) {
+ throw new IllegalArgumentException(
+ "Trying to set an admin which is being removed");
+ }
ActiveAdmin newAdmin = new ActiveAdmin(info, /* parent */ false);
policy.mAdminMap.put(adminReceiver, newAdmin);
int replaceIndex = -1;
@@ -2958,7 +3010,7 @@
ArrayList<ActiveAdmin> admins = new ArrayList<ActiveAdmin>();
for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) {
DevicePolicyData policy = getUserData(userInfo.id);
- if (!isManagedProfile(userInfo.id)) {
+ if (!userInfo.isManagedProfile()) {
admins.addAll(policy.mAdminList);
} else {
// For managed profiles, we always include the policies set on the parent
@@ -3692,32 +3744,26 @@
final int callingUid = mInjector.binderGetCallingUid();
final int userHandle = mInjector.userHandleGetCallingUserId();
- if (getCredentialOwner(userHandle, /* parent */ false) != userHandle) {
- throw new SecurityException("You can not change password for this profile because"
- + " it shares the password with the owner profile");
- }
-
String password = passwordOrNull != null ? passwordOrNull : "";
+ // Password resetting to empty/null is not allowed for managed profiles.
+ if (TextUtils.isEmpty(password)) {
+ enforceNotManagedProfile(userHandle, "clear the active password");
+ }
+
int quality;
synchronized (this) {
- // If caller has PO (or DO), it can clear the password, so see if that's the case
- // first.
+ // If caller has PO (or DO) it can change the password, so see if that's the case first.
ActiveAdmin admin = getActiveAdminWithPolicyForUidLocked(
null, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, callingUid);
if (admin == null) {
// Otherwise, make sure the caller has any active admin with the right policy.
admin = getActiveAdminForCallerLocked(null,
DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
- }
- final ComponentName adminComponent = admin.info.getComponent();
-
- // As of N, only profile owners and device owners can reset the password.
- if (!(isProfileOwner(adminComponent, userHandle)
- || isDeviceOwner(adminComponent, userHandle))) {
final boolean preN = getTargetSdk(admin.info.getPackageName(), userHandle)
<= android.os.Build.VERSION_CODES.M;
+
// As of N, password resetting to empty/null is not allowed anymore.
// TODO Should we allow DO/PO to set an empty password?
if (TextUtils.isEmpty(password)) {
@@ -3846,6 +3892,9 @@
// back in to the service.
final long ident = mInjector.binderClearCallingIdentity();
try {
+ if (isManagedProfile(userHandle)) {
+ mLockPatternUtils.setSeparateProfileChallengeEnabled(userHandle, true);
+ }
if (!TextUtils.isEmpty(password)) {
mLockPatternUtils.saveLockPassword(password, null, quality, userHandle);
} else {
@@ -4070,6 +4119,29 @@
}
@Override
+ public boolean approveCaCert(String alias, int userId, boolean approval) {
+ enforceManageUsers();
+ synchronized (this) {
+ Set<String> certs = getUserData(userId).mAcceptedCaCertificates;
+ boolean changed = (approval ? certs.add(alias) : certs.remove(alias));
+ if (!changed) {
+ return false;
+ }
+ saveSettingsLocked(userId);
+ }
+ new MonitoringCertNotificationTask().execute(userId);
+ return true;
+ }
+
+ @Override
+ public boolean isCaCertApproved(String alias, int userId) {
+ enforceManageUsers();
+ synchronized (this) {
+ return getUserData(userId).mAcceptedCaCertificates.contains(alias);
+ }
+ }
+
+ @Override
public boolean installCaCert(ComponentName admin, byte[] certBuffer) throws RemoteException {
enforceCanManageCaCerts(admin);
@@ -7847,9 +7919,9 @@
super(handler);
}
- void register(ContentResolver resolver) {
- resolver.registerContentObserver(mUserSetupComplete, false, this, UserHandle.USER_ALL);
- resolver.registerContentObserver(mDeviceProvisioned, false, this, UserHandle.USER_ALL);
+ void register() {
+ mInjector.registerContentObserver(mUserSetupComplete, false, this, UserHandle.USER_ALL);
+ mInjector.registerContentObserver(mDeviceProvisioned, false, this, UserHandle.USER_ALL);
}
@Override
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b026bc5..81e43fd 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -155,6 +155,10 @@
"com.android.server.search.SearchManagerService$Lifecycle";
private static final String THERMAL_OBSERVER_CLASS =
"com.google.android.clockwork.ThermalObserver";
+ private static final String WEAR_BLUETOOTH_SERVICE_CLASS =
+ "com.google.android.clockwork.bluetooth.WearBluetoothService";
+ private static final String CONTENT_SERVICE_CLASS =
+ "com.android.server.content.ContentService$Lifecycle";
private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
@@ -167,7 +171,7 @@
* visual content.
*/
private static final int DEFAULT_SYSTEM_THEME =
- com.android.internal.R.style.Theme_Material_DayNight_DarkActionBar;
+ com.android.internal.R.style.Theme_Material_Light_DarkActionBar;
private final int mFactoryTestMode;
private Timer mProfilerSnapshotTimer;
@@ -572,8 +576,7 @@
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
traceBeginAndSlog("StartContentService");
- contentService = ContentService.main(context,
- mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL);
+ mSystemServiceManager.startService(CONTENT_SERVICE_CLASS);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
traceBeginAndSlog("InstallSystemProviders");
@@ -959,8 +962,7 @@
if (!disableNonCoreServices) {
mSystemServiceManager.startService(DockObserver.class);
- if (context.getPackageManager().hasSystemFeature
- (PackageManager.FEATURE_WATCH)) {
+ if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
mSystemServiceManager.startService(THERMAL_OBSERVER_CLASS);
}
}
@@ -1172,6 +1174,10 @@
mSystemServiceManager.startService(MediaProjectionManagerService.class);
}
+ if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ mSystemServiceManager.startService(WEAR_BLUETOOTH_SERVICE_CLASS);
+ }
+
// Before things start rolling, be sure we have decided whether
// we are in safe mode.
final boolean safeMode = wm.detectSafeMode();
@@ -1319,7 +1325,7 @@
reportWtf("starting System UI", e);
}
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
- Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeMountServiceReady");
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeNetworkScoreReady");
try {
if (networkScoreF != null) networkScoreF.systemReady();
} catch (Throwable e) {
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index ebbf991..f430a30 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -18,6 +18,7 @@
import static android.system.OsConstants.*;
+import android.net.LinkProperties;
import android.net.NetworkUtils;
import android.net.apf.ApfGenerator;
import android.net.apf.ApfGenerator.IllegalInstructionException;
@@ -136,6 +137,16 @@
// NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 28;
+ private static int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
+ private static final byte[] ARP_IPV4_REQUEST_HEADER = new byte[]{
+ 0, 1, // Hardware type: Ethernet (1)
+ 8, 0, // Protocol type: IP (0x0800)
+ 6, // Hardware size: 6
+ 4, // Protocol size: 4
+ 0, 1 // Opcode: request (1)
+ };
+ private static int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
+
private final ApfCapabilities mApfCapabilities;
private final IpManager.Callback mIpManagerCallback;
private final NetworkInterface mNetworkInterface;
@@ -145,12 +156,16 @@
private long mUniqueCounter;
@GuardedBy("this")
private boolean mMulticastFilter;
+ // Our IPv4 address, if we have just one, otherwise null.
+ @GuardedBy("this")
+ private byte[] mIPv4Address;
private ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface,
- IpManager.Callback ipManagerCallback) {
+ IpManager.Callback ipManagerCallback, boolean multicastFilter) {
mApfCapabilities = apfCapabilities;
mIpManagerCallback = ipManagerCallback;
mNetworkInterface = networkInterface;
+ mMulticastFilter = multicastFilter;
maybeStartFilter();
}
@@ -225,6 +240,7 @@
private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
+ // Note: mPacket's position() cannot be assumed to be reset.
private final ByteBuffer mPacket;
// List of binary ranges that include the whole packet except the lifetimes.
// Pairs consist of offset and length.
@@ -378,17 +394,12 @@
// Ignoring lifetimes (which may change) does {@code packet} match this RA?
boolean matches(byte[] packet, int length) {
- if (length != mPacket.limit()) return false;
- ByteBuffer a = ByteBuffer.wrap(packet);
- ByteBuffer b = mPacket;
+ if (length != mPacket.capacity()) return false;
+ byte[] referencePacket = mPacket.array();
for (Pair<Integer, Integer> nonLifetime : mNonLifetimes) {
- a.clear();
- b.clear();
- a.position(nonLifetime.first);
- b.position(nonLifetime.first);
- a.limit(nonLifetime.first + nonLifetime.second);
- b.limit(nonLifetime.first + nonLifetime.second);
- if (a.compareTo(b) != 0) return false;
+ for (int i = nonLifetime.first; i < (nonLifetime.first + nonLifetime.second); i++) {
+ if (packet[i] != referencePacket[i]) return false;
+ }
}
return true;
}
@@ -440,7 +451,7 @@
String nextFilterLabel = "Ra" + getUniqueNumberLocked();
// Skip if packet is not the right size
gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT);
- gen.addJumpIfR0NotEquals(mPacket.limit(), nextFilterLabel);
+ gen.addJumpIfR0NotEquals(mPacket.capacity(), nextFilterLabel);
int filterLifetime = (int)(currentLifetime() / FRACTION_OF_LIFETIME_TO_FILTER);
// Skip filter if expired
gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT);
@@ -510,6 +521,33 @@
private byte[] mLastInstalledProgram;
/**
+ * Generate filter code to process ARP packets. Execution of this code ends in either the
+ * DROP_LABEL or PASS_LABEL and does not fall off the end.
+ * Preconditions:
+ * - Packet being filtered is ARP
+ */
+ @GuardedBy("this")
+ private void generateArpFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
+ // Here's a basic summary of what the ARP filter program does:
+ //
+ // if it's not an ARP IPv4 request:
+ // pass
+ // if it's not a request for our IPv4 address:
+ // drop
+ // pass
+
+ // if it's not an ARP IPv4 request, pass
+ gen.addLoadImmediate(Register.R0, ARP_HEADER_OFFSET);
+ gen.addJumpIfBytesNotEqual(Register.R0, ARP_IPV4_REQUEST_HEADER, gen.PASS_LABEL);
+ // if it's not a request for our IPv4 address, drop
+ gen.addLoadImmediate(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
+ gen.addJumpIfBytesNotEqual(Register.R0, mIPv4Address, gen.DROP_LABEL);
+
+ // Otherwise, pass
+ gen.addJump(gen.PASS_LABEL);
+ }
+
+ /**
* Generate filter code to process IPv4 packets. Execution of this code ends in either the
* DROP_LABEL or PASS_LABEL and does not fall off the end.
* Preconditions:
@@ -566,7 +604,6 @@
* DROP_LABEL or PASS_LABEL, or falls off the end for ICMPv6 packets.
* Preconditions:
* - Packet being filtered is IPv6
- * - R1 is initialized to 0
*/
@GuardedBy("this")
private void generateIPv6FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
@@ -598,6 +635,7 @@
/**
* Begin generating an APF program to:
* <ul>
+ * <li>Drop ARP requests not for us, if mIPv4Address is set,
* <li>Drop IPv4 broadcast packets, except DHCP destined to our MAC,
* <li>Drop IPv4 multicast packets, if mMulticastFilter,
* <li>Pass all other IPv4 packets,
@@ -616,16 +654,31 @@
// Here's a basic summary of what the initial program does:
//
+ // if it's ARP:
+ // inesrt ARP filter to drop or pass these appropriately
// if it's IPv4:
// insert IPv4 filter to drop or pass these appropriately
// if it's not IPv6:
// pass
// insert IPv6 filter to drop, pass, or fall off the end for ICMPv6 packets
+ gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET);
+
+ if (mIPv4Address != null) {
+ // Add ARP filters:
+ String skipArpFiltersLabel = "skipArpFilters";
+ // If not ARP, skip ARP filters
+ // NOTE: Relies on R0 containing ethertype.
+ gen.addJumpIfR0NotEquals(ETH_P_ARP, skipArpFiltersLabel);
+ generateArpFilterLocked(gen);
+ gen.defineLabel(skipArpFiltersLabel);
+ }
+
// Add IPv4 filters:
String skipIPv4FiltersLabel = "skipIPv4Filters";
- // If not IPv4, skip IPv4 filters
- gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET);
+ // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not
+ // execute the ARP filter, since that filter does not fall through, but either drops or
+ // passes.
gen.addJumpIfR0NotEquals(ETH_P_IP, skipIPv4FiltersLabel);
// NOTE: Relies on R1 being initialized to 0.
generateIPv4FilterLocked(gen);
@@ -634,8 +687,8 @@
// Add IPv6 filters:
// If not IPv6, pass
// NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not
- // execute the IPv4 filter, since that filter does not fall through, but either drops or
- // passes.
+ // execute the ARP or IPv4 filters, since those filters do not fall through, but either
+ // drop or pass.
gen.addJumpIfR0NotEquals(ETH_P_IPV6, gen.PASS_LABEL);
generateIPv6FilterLocked(gen);
return gen;
@@ -752,7 +805,8 @@
* filtering using APF programs.
*/
public static ApfFilter maybeCreate(ApfCapabilities apfCapabilities,
- NetworkInterface networkInterface, IpManager.Callback ipManagerCallback) {
+ NetworkInterface networkInterface, IpManager.Callback ipManagerCallback,
+ boolean multicastFilter) {
if (apfCapabilities == null || networkInterface == null) return null;
if (apfCapabilities.apfVersionSupported == 0) return null;
if (apfCapabilities.maximumApfProgramSize < 512) {
@@ -768,7 +822,7 @@
Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
return null;
}
- return new ApfFilter(apfCapabilities, networkInterface, ipManagerCallback);
+ return new ApfFilter(apfCapabilities, networkInterface, ipManagerCallback, multicastFilter);
}
public synchronized void shutdown() {
@@ -787,10 +841,36 @@
}
}
+ // Find the single IPv4 address if there is one, otherwise return null.
+ private static byte[] findIPv4Address(LinkProperties lp) {
+ byte[] ipv4Address = null;
+ for (InetAddress inetAddr : lp.getAddresses()) {
+ byte[] addr = inetAddr.getAddress();
+ if (addr.length != 4) continue;
+ // More than one IPv4 address, abort
+ if (ipv4Address != null && !Arrays.equals(ipv4Address, addr)) return null;
+ ipv4Address = addr;
+ }
+ return ipv4Address;
+ }
+
+ public synchronized void setLinkProperties(LinkProperties lp) {
+ // NOTE: Do not keep a copy of LinkProperties as it would further duplicate state.
+ byte[] ipv4Address = findIPv4Address(lp);
+ // If ipv4Address is the same as mIPv4Address, then there's no change, just return.
+ if (Arrays.equals(ipv4Address, mIPv4Address)) return;
+ // Otherwise update mIPv4Address and install new program.
+ mIPv4Address = ipv4Address;
+ installNewProgramLocked();
+ }
+
public synchronized void dump(IndentingPrintWriter pw) {
- pw.println("APF version: " + mApfCapabilities.apfVersionSupported);
- pw.println("Max program size: " + mApfCapabilities.maximumApfProgramSize);
+ pw.println("APF caps: " + mApfCapabilities);
pw.println("Receive thread: " + (mReceiveThread != null ? "RUNNING" : "STOPPED"));
+ pw.println("Multicast filtering: " + mMulticastFilter);
+ try {
+ pw.println("IPv4 address: " + InetAddress.getByAddress(mIPv4Address));
+ } catch (UnknownHostException|NullPointerException e) {}
if (mLastTimeInstalledProgram == 0) {
pw.println("No program installed.");
return;
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
index e27f69e..a881408 100644
--- a/services/net/java/android/net/dhcp/DhcpPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
@@ -57,6 +57,17 @@
public static final int HWADDR_LEN = 16;
public static final int MAX_OPTION_LEN = 255;
+
+ /**
+ * The minimum and maximum MTU that we are prepared to use. We set the minimum to the minimum
+ * IPv6 MTU because the IPv6 stack enters unusual codepaths when the link MTU drops below 1280,
+ * and does not recover if the MTU is brought above 1280 again. We set the maximum to 1500
+ * because in general it is risky to assume that the hardware is able to send/receive packets
+ * larger than 1500 bytes even if the network supports it.
+ */
+ private static final int MIN_MTU = 1280;
+ private static final int MAX_MTU = 1500;
+
/**
* IP layer definitions.
*/
@@ -917,7 +928,7 @@
break;
case DHCP_MTU:
expectedLen = 2;
- mtu = Short.valueOf(packet.getShort());
+ mtu = packet.getShort();
break;
case DHCP_DOMAIN_NAME:
expectedLen = optionLen;
@@ -1106,6 +1117,8 @@
results.serverAddress = mServerIdentifier;
results.vendorInfo = mVendorInfo;
results.leaseDuration = (mLeaseTime != null) ? mLeaseTime : INFINITE_LEASE;
+ results.mtu = (mMtu != null && MIN_MTU <= mMtu && mMtu <= MAX_MTU) ? mMtu : 0;
+
return results;
}
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index c25fae3..54aeb3d 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -100,10 +100,6 @@
public void onProvisioningSuccess(LinkProperties newLp) {}
public void onProvisioningFailure(LinkProperties newLp) {}
- // This is called whenever 464xlat is being enabled or disabled (i.e.
- // started or stopped).
- public void on464XlatChange(boolean enabled) {}
-
// Invoked on LinkProperties changes.
public void onLinkPropertiesChange(LinkProperties newLp) {}
@@ -116,6 +112,14 @@
// Install an APF program to filter incoming packets.
public void installPacketFilter(byte[] filter) {}
+
+ // If multicast filtering cannot be accomplished with APF, this function will be called to
+ // actuate multicast filtering using another means.
+ public void setFallbackMulticastFilter(boolean enabled) {}
+
+ // Enabled/disable Neighbor Discover offload functionality. This is
+ // called, for example, whenever 464xlat is being started or stopped.
+ public void setNeighborDiscoveryOffload(boolean enable) {}
}
public static class WaitForProvisioningCallback extends Callback {
@@ -222,6 +226,7 @@
private static final int EVENT_NETLINK_LINKPROPERTIES_CHANGED = 5;
private static final int CMD_UPDATE_TCP_BUFFER_SIZES = 6;
private static final int CMD_UPDATE_HTTP_PROXY = 7;
+ private static final int CMD_SET_MULTICAST_FILTER = 8;
private static final int MAX_LOG_RECORDS = 1000;
@@ -258,6 +263,7 @@
private String mTcpBufferSizes;
private ProxyInfo mHttpProxy;
private ApfFilter mApfFilter;
+ private boolean mMulticastFiltering;
/**
* Member variables accessed both from within the StateMachine thread
@@ -296,15 +302,20 @@
}) {
@Override
public void interfaceAdded(String iface) {
+ super.interfaceAdded(iface);
if (mClatInterfaceName.equals(iface)) {
- mCallback.on464XlatChange(true);
+ mCallback.setNeighborDiscoveryOffload(false);
}
}
@Override
public void interfaceRemoved(String iface) {
+ super.interfaceRemoved(iface);
if (mClatInterfaceName.equals(iface)) {
- mCallback.on464XlatChange(false);
+ // TODO: consider sending a message to the IpManager main
+ // StateMachine thread, in case "NDO enabled" state becomes
+ // tied to more things that 464xlat operation.
+ mCallback.setNeighborDiscoveryOffload(true);
}
}
};
@@ -390,6 +401,14 @@
sendMessage(CMD_UPDATE_HTTP_PROXY, proxyInfo);
}
+ /**
+ * Enable or disable the multicast filter. Attempts to use APF to accomplish the filtering,
+ * if not, Callback.setFallbackMulticastFilter() is called.
+ */
+ public void setMulticastFilter(boolean enabled) {
+ sendMessage(CMD_SET_MULTICAST_FILTER, enabled);
+ }
+
public LinkProperties getLinkProperties() {
synchronized (mLock) {
return new LinkProperties(mLinkProperties);
@@ -519,6 +538,7 @@
}
private void dispatchCallback(ProvisioningChange delta, LinkProperties newLp) {
+ if (mApfFilter != null) mApfFilter.setLinkProperties(newLp);
switch (delta) {
case GAINED_PROVISIONING:
if (VDBG) { Log.d(mTag, "onProvisioningSuccess()"); }
@@ -605,6 +625,10 @@
}
}
newLp.setDomains(mDhcpResults.domains);
+
+ if (mDhcpResults.mtu != 0) {
+ newLp.setMtu(mDhcpResults.mtu);
+ }
}
// [4] Add in TCP buffer sizes and HTTP Proxy config, if available.
@@ -725,6 +749,10 @@
handleLinkPropertiesUpdate(NO_CALLBACKS);
break;
+ case CMD_SET_MULTICAST_FILTER:
+ mMulticastFiltering = (boolean) msg.obj;
+ break;
+
case DhcpClient.CMD_ON_QUIT:
// Everything is already stopped.
Log.e(mTag, "Unexpected CMD_ON_QUIT (already stopped).");
@@ -765,7 +793,10 @@
@Override
public void enter() {
mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface,
- mCallback);
+ mCallback, mMulticastFiltering);
+ // TODO: investigate the effects of any multicast filtering racing/interfering with the
+ // rest of this IP configuration startup.
+ if (mApfFilter == null) mCallback.setFallbackMulticastFilter(mMulticastFiltering);
// Set privacy extensions.
try {
mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
@@ -878,6 +909,16 @@
handleLinkPropertiesUpdate(SEND_CALLBACKS);
break;
+ case CMD_SET_MULTICAST_FILTER: {
+ mMulticastFiltering = (boolean) msg.obj;
+ if (mApfFilter != null) {
+ mApfFilter.setMulticastFilter(mMulticastFiltering);
+ } else {
+ mCallback.setFallbackMulticastFilter(mMulticastFiltering);
+ }
+ break;
+ }
+
case DhcpClient.CMD_PRE_DHCP_ACTION:
if (VDBG) { Log.d(mTag, "onPreDhcpAction()"); }
if (mConfiguration.mRequestedPreDhcpAction) {
diff --git a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
index 876d95b..f8eaf7d 100644
--- a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
+++ b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
@@ -261,7 +261,7 @@
private void assertDhcpResults(String ipAddress, String gateway, String dnsServersString,
String domains, String serverAddress, String vendorInfo, int leaseDuration,
- boolean hasMeteredHint, DhcpResults dhcpResults) throws Exception {
+ boolean hasMeteredHint, int mtu, DhcpResults dhcpResults) throws Exception {
assertEquals(new LinkAddress(ipAddress), dhcpResults.ipAddress);
assertEquals(v4Address(gateway), dhcpResults.gateway);
@@ -277,6 +277,7 @@
assertEquals(vendorInfo, dhcpResults.vendorInfo);
assertEquals(leaseDuration, dhcpResults.leaseDuration);
assertEquals(hasMeteredHint, dhcpResults.hasMeteredHint());
+ assertEquals(mtu, dhcpResults.mtu);
}
@SmallTest
@@ -310,7 +311,7 @@
assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("192.168.159.247/20", "192.168.159.254", "8.8.8.8,8.8.4.4",
- null, "192.168.144.3", null, 7200, false, dhcpResults);
+ null, "192.168.144.3", null, 7200, false, 0, dhcpResults);
}
@SmallTest
@@ -342,10 +343,70 @@
assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("192.168.43.247/24", "192.168.43.1", "192.168.43.1",
- null, "192.168.43.1", "ANDROID_METERED", 3600, true, dhcpResults);
+ null, "192.168.43.1", "ANDROID_METERED", 3600, true, 0, dhcpResults);
assertTrue(dhcpResults.hasMeteredHint());
}
+ private byte[] mtuBytes(int mtu) {
+ // 0x1a02: option 26, length 2. 0xff: no more options.
+ if (mtu > Short.MAX_VALUE - Short.MIN_VALUE) {
+ throw new IllegalArgumentException(
+ String.format("Invalid MTU %d, must be 16-bit unsigned", mtu));
+ }
+ String hexString = String.format("1a02%04xff", mtu);
+ return HexEncoding.decode(hexString.toCharArray(), false);
+ }
+
+ private void checkMtu(ByteBuffer packet, int expectedMtu, byte[] mtuBytes) throws Exception {
+ if (mtuBytes != null) {
+ packet.position(packet.capacity() - mtuBytes.length);
+ packet.put(mtuBytes);
+ packet.clear();
+ }
+ DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+ assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
+ DhcpResults dhcpResults = offerPacket.toDhcpResults();
+ assertDhcpResults("192.168.159.247/20", "192.168.159.254", "8.8.8.8,8.8.4.4",
+ null, "192.168.144.3", null, 7200, false, expectedMtu, dhcpResults);
+ }
+
+ @SmallTest
+ public void testMtu() throws Exception {
+ final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+ // IP header.
+ "451001480000000080118849c0a89003c0a89ff7" +
+ // UDP header.
+ "004300440134dcfa" +
+ // BOOTP header.
+ "02010600c997a63b0000000000000000c0a89ff70000000000000000" +
+ // MAC address.
+ "30766ff2a90c00000000000000000000" +
+ // Server name.
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ // File.
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ // Options
+ "638253633501023604c0a89003330400001c200104fffff0000304c0a89ffe06080808080808080404" +
+ "3a0400000e103b040000189cff00000000"
+ ).toCharArray(), false));
+
+ checkMtu(packet, 0, null);
+ checkMtu(packet, 0, mtuBytes(1501));
+ checkMtu(packet, 1500, mtuBytes(1500));
+ checkMtu(packet, 1499, mtuBytes(1499));
+ checkMtu(packet, 1280, mtuBytes(1280));
+ checkMtu(packet, 0, mtuBytes(1279));
+ checkMtu(packet, 0, mtuBytes(576));
+ checkMtu(packet, 0, mtuBytes(68));
+ checkMtu(packet, 0, mtuBytes(Short.MIN_VALUE));
+ checkMtu(packet, 0, mtuBytes(Short.MAX_VALUE + 3));
+ checkMtu(packet, 0, mtuBytes(-1));
+ }
+
@SmallTest
public void testBadHwaddrLength() throws Exception {
final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
@@ -453,7 +514,7 @@
assertTrue(offerPacket instanceof DhcpOfferPacket);
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("172.17.152.118/16", "172.17.1.1", "172.17.1.1",
- null, "1.1.1.1", null, 43200, false, dhcpResults);
+ null, "1.1.1.1", null, 43200, false, 0, dhcpResults);
}
@SmallTest
@@ -484,7 +545,7 @@
assertTrue(offerPacket instanceof DhcpOfferPacket);
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("10.63.93.4/20", "10.63.80.1", "192.0.2.1,192.0.2.2",
- "domain123.co.uk", "192.0.2.254", null, 49094, false, dhcpResults);
+ "domain123.co.uk", "192.0.2.254", null, 49094, false, 0, dhcpResults);
}
@SmallTest
@@ -518,7 +579,7 @@
assertEquals("BCF5AC000000", HexDump.toHexString(offerPacket.getClientMac()));
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("10.32.158.205/20", "10.32.144.1", "148.88.65.52,148.88.65.53",
- "lancs.ac.uk", "10.32.255.128", null, 7200, false, dhcpResults);
+ "lancs.ac.uk", "10.32.255.128", null, 7200, false, 0, dhcpResults);
}
@SmallTest
@@ -554,7 +615,7 @@
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("10.15.122.242/16", "10.15.200.23",
"209.129.128.3,209.129.148.3,209.129.128.6",
- "wvm.edu", "10.1.105.252", null, 86400, false, dhcpResults);
+ "wvm.edu", "10.1.105.252", null, 86400, false, 0, dhcpResults);
}
@SmallTest
@@ -621,7 +682,7 @@
assertEquals("FC3D93000000", HexDump.toHexString(offerPacket.getClientMac()));
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("192.168.189.49/24", "192.168.189.1", "8.8.8.8,8.8.4.4",
- null, "192.171.189.2", null, 28800, false, dhcpResults);
+ null, "192.171.189.2", null, 28800, false, 0, dhcpResults);
}
@SmallTest
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 35777ce..744443f 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -15,14 +15,14 @@
*/
package com.android.server.devicepolicy;
-import com.android.internal.widget.LockPatternUtils;
-
import android.app.IActivityManager;
import android.app.NotificationManager;
import android.app.backup.IBackupManager;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManagerInternal;
+import android.database.ContentObserver;
import android.media.IAudioService;
+import android.net.Uri;
import android.os.Looper;
import android.os.PowerManagerInternal;
import android.os.UserHandle;
@@ -30,12 +30,15 @@
import android.os.UserManagerInternal;
import android.os.storage.StorageManager;
import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Pair;
import android.view.IWindowManager;
-import java.io.File;
+import com.android.internal.widget.LockPatternUtils;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.when;
+import java.io.File;
+import java.util.Map;
/**
* Overrides {@link #DevicePolicyManagerService} for dependency injection.
@@ -77,6 +80,7 @@
}
public final DpmMockContext context;
+ private final MockInjector mMockInjector;
public DevicePolicyManagerServiceTestable(DpmMockContext context, File dataDir) {
this(new MockInjector(context, dataDir));
@@ -84,15 +88,36 @@
private DevicePolicyManagerServiceTestable(MockInjector injector) {
super(injector);
+ mMockInjector = injector;
this.context = injector.context;
}
+
+ public void notifyChangeToContentObserver(Uri uri, int userHandle) {
+ ContentObserver co = mMockInjector.mContentObservers
+ .get(new Pair<Uri, Integer>(uri, userHandle));
+ if (co != null) {
+ co.onChange(false, uri, userHandle); // notify synchronously
+ }
+
+ // Notify USER_ALL observer too.
+ co = mMockInjector.mContentObservers
+ .get(new Pair<Uri, Integer>(uri, UserHandle.USER_ALL));
+ if (co != null) {
+ co.onChange(false, uri, userHandle); // notify synchronously
+ }
+ }
+
+
private static class MockInjector extends Injector {
public final DpmMockContext context;
public final File dataDir;
+ // Key is a pair of uri and userId
+ private final Map<Pair<Uri, Integer>, ContentObserver> mContentObservers = new ArrayMap<>();
+
private MockInjector(DpmMockContext context, File dataDir) {
super(context);
this.context = context;
@@ -265,6 +290,12 @@
}
@Override
+ void registerContentObserver(Uri uri, boolean notifyForDescendents,
+ ContentObserver observer, int userHandle) {
+ mContentObservers.put(new Pair<Uri, Integer>(uri, userHandle), observer);
+ }
+
+ @Override
int settingsSecureGetIntForUser(String name, int def, int userHandle) {
return context.settings.settingsSecureGetIntForUser(name, def, userHandle);
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index e6963d5..3a2e946 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -543,10 +543,31 @@
}
/**
- * Test for: {@link DevicePolicyManager#setDeviceOwner} DO on system user installs
- * successfully.
+ * Test for: {@link DevicePolicyManager#setDeviceOwner} DO on system user installs successfully.
*/
public void testSetDeviceOwner() throws Exception {
+ setDeviceOwner();
+
+ // Try to set a profile owner on the same user, which should fail.
+ setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
+ dpm.setActiveAdmin(admin2, /* refreshing= */ true, UserHandle.USER_SYSTEM);
+ try {
+ dpm.setProfileOwner(admin2, "owner-name", UserHandle.USER_SYSTEM);
+ fail("IllegalStateException not thrown");
+ } catch (IllegalStateException expected) {
+ assertTrue("Message was: " + expected.getMessage(),
+ expected.getMessage().contains("already has a device owner"));
+ }
+
+ // DO admin can't be deactivated.
+ dpm.removeActiveAdmin(admin1);
+ assertTrue(dpm.isAdminActive(admin1));
+
+ // TODO Test getDeviceOwnerName() too. To do so, we need to change
+ // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
+ }
+
+ private void setDeviceOwner() throws Exception {
mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
mContext.callerPermissions.add(permission.MANAGE_USERS);
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
@@ -594,24 +615,6 @@
MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
-
- // Try to set a profile owner on the same user, which should fail.
- setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
- dpm.setActiveAdmin(admin2, /* refreshing= */ true, UserHandle.USER_SYSTEM);
- try {
- dpm.setProfileOwner(admin2, "owner-name", UserHandle.USER_SYSTEM);
- fail("IllegalStateException not thrown");
- } catch (IllegalStateException expected) {
- assertTrue("Message was: " + expected.getMessage(),
- expected.getMessage().contains("already has a device owner"));
- }
-
- // DO admin can't be deactivated.
- dpm.removeActiveAdmin(admin1);
- assertTrue(dpm.isAdminActive(admin1));
-
- // TODO Test getDeviceOwnerName() too. To do so, we need to change
- // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
}
private void checkGetDeviceOwnerInfoApi(DevicePolicyManager dpm, boolean hasDeviceOwner) {
@@ -1934,5 +1937,211 @@
// TODO Verify calls to settingsGlobalPutInt. Tried but somehow mockito threw
// UnfinishedVerificationException.
}
-}
+ public void testIsProvisioningAllowed_DeviceAdminFeatureOff() throws Exception {
+ when(mContext.packageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN))
+ .thenReturn(false);
+ when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+ .thenReturn(false);
+ initializeDpms();
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
+ when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+ .thenReturn(true);
+ setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, false);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+ false);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false);
+ }
+
+ public void testIsProvisioningAllowed_ManagedProfileFeatureOff() throws Exception {
+ when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+ .thenReturn(false);
+ initializeDpms();
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
+ when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+ .thenReturn(true);
+ setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+ false);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false);
+
+ // Test again when split user is on
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+ true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false);
+ }
+
+ public void testIsProvisioningAllowed_nonSplitUser_firstBoot_primaryUser() throws Exception {
+ when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+ .thenReturn(true);
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
+ when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+ .thenReturn(true);
+ setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+ false /* because of non-split user */);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+ false /* because of non-split user */);
+ }
+
+ public void testIsProvisioningAllowed_nonSplitUser_afterDeviceSetup_primaryUser()
+ throws Exception {
+ when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+ .thenReturn(true);
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
+ when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+ .thenReturn(true);
+ setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+ false/* because of completed device setup */);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+ false/* because of non-split user */);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+ false/* because of non-split user */);
+ }
+
+ public void testIsProvisioningAllowed_splitUser_firstBoot_systemUser() throws Exception {
+ when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+ .thenReturn(true);
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+ when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+ .thenReturn(false);
+ setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+ false /* because canAddMoreManagedProfiles returns false */);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+ true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+ false/* because calling uid is system user */);
+
+ }
+
+ public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_systemUser() throws Exception {
+ when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+ .thenReturn(true);
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+ when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+ .thenReturn(false);
+ setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+ true/* it's undefined behavior. Can be changed into false in the future */);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+ false /* because canAddMoreManagedProfiles returns false */);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+ true/* it's undefined behavior. Can be changed into false in the future */);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+ false/* because calling uid is system user */);
+ }
+
+ public void testIsProvisioningAllowed_splitUser_firstBoot_primaryUser() throws Exception {
+ when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+ .thenReturn(true);
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+ when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
+ true)).thenReturn(true);
+ setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+ true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, true);
+
+ }
+
+ public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_primaryUser()
+ throws Exception {
+ when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+ .thenReturn(true);
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+ when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
+ true)).thenReturn(true);
+ setUserSetupCompleteForUser(true, DpmMockContext.CALLER_USER_HANDLE);
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+ true/* it's undefined behavior. Can be changed into false in the future */);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+ true/* it's undefined behavior. Can be changed into false in the future */);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+ false/* because user setup completed */);
+ }
+
+ public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_systemUser()
+ throws Exception {
+ setDeviceOwner();
+
+ when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+ .thenReturn(true);
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+ when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+ .thenReturn(false);
+ setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+ false /* can't provision managed profile on system user */);
+ }
+
+ public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_primaryUser()
+ throws Exception {
+ setDeviceOwner();
+
+ when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+ .thenReturn(true);
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+ when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
+ true)).thenReturn(true);
+ setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+ }
+
+ private void setUserSetupCompleteForUser(boolean isUserSetupComplete, int userhandle) {
+ when(mContext.settings.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0,
+ userhandle)).thenReturn(isUserSetupComplete ? 1 : 0);
+ dpms.notifyChangeToContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), userhandle);
+ }
+
+ private void assertProvisioningAllowed(String action, boolean expected) {
+ assertEquals("isProvisioningAllowed(" + action + ") returning unexpected result", expected,
+ dpm.isProvisioningAllowed(action));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 8e2ef70..60d7382 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -53,6 +53,7 @@
import java.util.ArrayList;
import java.util.List;
+import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
@@ -172,36 +173,36 @@
}
public static class SettingsForMock {
- int settingsSecureGetIntForUser(String name, int def, int userHandle) {
+ public int settingsSecureGetIntForUser(String name, int def, int userHandle) {
return 0;
}
- void settingsSecurePutIntForUser(String name, int value, int userHandle) {
+ public void settingsSecurePutIntForUser(String name, int value, int userHandle) {
}
- void settingsSecurePutStringForUser(String name, String value, int userHandle) {
+ public void settingsSecurePutStringForUser(String name, String value, int userHandle) {
}
- void settingsGlobalPutStringForUser(String name, String value, int userHandle) {
+ public void settingsGlobalPutStringForUser(String name, String value, int userHandle) {
}
- void settingsSecurePutInt(String name, int value) {
+ public void settingsSecurePutInt(String name, int value) {
}
- void settingsGlobalPutInt(String name, int value) {
+ public void settingsGlobalPutInt(String name, int value) {
}
- void settingsSecurePutString(String name, String value) {
+ public void settingsSecurePutString(String name, String value) {
}
- void settingsGlobalPutString(String name, String value) {
+ public void settingsGlobalPutString(String name, String value) {
}
- int settingsGlobalGetInt(String name, int def) {
+ public int settingsGlobalGetInt(String name, int value) {
return 0;
}
- void securityLogSetLoggingEnabledProperty(boolean enabled) {
+ public void securityLogSetLoggingEnabledProperty(boolean enabled) {
}
public boolean securityLogGetLoggingEnabledProperty() {
@@ -321,6 +322,8 @@
mUserInfos.add(uh);
when(userManager.getUsers()).thenReturn(mUserInfos);
+ when(userManager.getUsers(anyBoolean())).thenReturn(mUserInfos);
+ when(userManager.isUserRunning(eq(new UserHandle(userId)))).thenReturn(true);
when(userManager.getUserInfo(anyInt())).thenAnswer(
new Answer<UserInfo>() {
@Override
diff --git a/services/tests/servicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/servicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
new file mode 100644
index 0000000..83a59fd
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -0,0 +1,541 @@
+/*
+ * Copyright (C) 2016 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.notification;
+
+
+import android.app.ActivityManager;
+import android.app.Notification;
+import android.app.Notification.Builder;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.Vibrator;
+import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.StatusBarNotification;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class BuzzBeepBlinkTest extends AndroidTestCase {
+
+ @Mock AudioManager mAudioManager;
+ @Mock Vibrator mVibrator;
+ @Mock android.media.IRingtonePlayer mRingtonePlayer;
+ @Mock Handler mHandler;
+
+ private NotificationManagerService mService;
+ private String mPkg = "com.android.server.notification";
+ private int mId = 1001;
+ private int mOtherId = 1002;
+ private String mTag = null;
+ private int mUid = 1000;
+ private int mPid = 2000;
+ private int mScore = 10;
+ private android.os.UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
+
+ @Override
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mAudioManager.isAudioFocusExclusive()).thenReturn(false);
+ when(mAudioManager.getRingtonePlayer()).thenReturn(mRingtonePlayer);
+ when(mAudioManager.getStreamVolume(anyInt())).thenReturn(10);
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
+
+ mService = new NotificationManagerService(getContext());
+ mService.setAudioManager(mAudioManager);
+ mService.setVibrator(mVibrator);
+ mService.setSystemReady(true);
+ mService.setHandler(mHandler);
+ }
+
+ //
+ // Convenience functions for creating notification records
+ //
+
+ private NotificationRecord getNoisyOtherNotification() {
+ return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
+ true /* noisy */, true /* buzzy*/);
+ }
+
+ private NotificationRecord getBeepyNotification() {
+ return getNotificationRecord(mId, false /* insistent */, false /* once */,
+ true /* noisy */, false /* buzzy*/);
+ }
+
+ private NotificationRecord getBeepyOnceNotification() {
+ return getNotificationRecord(mId, false /* insistent */, true /* once */,
+ true /* noisy */, false /* buzzy*/);
+ }
+
+ private NotificationRecord getQuietNotification() {
+ return getNotificationRecord(mId, false /* insistent */, false /* once */,
+ false /* noisy */, false /* buzzy*/);
+ }
+
+ private NotificationRecord getQuietOtherNotification() {
+ return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
+ false /* noisy */, false /* buzzy*/);
+ }
+
+ private NotificationRecord getQuietOnceNotification() {
+ return getNotificationRecord(mId, false /* insistent */, true /* once */,
+ false /* noisy */, false /* buzzy*/);
+ }
+
+ private NotificationRecord getInsistentBeepyNotification() {
+ return getNotificationRecord(mId, true /* insistent */, false /* once */,
+ true /* noisy */, false /* buzzy*/);
+ }
+
+ private NotificationRecord getBuzzyNotification() {
+ return getNotificationRecord(mId, false /* insistent */, false /* once */,
+ false /* noisy */, true /* buzzy*/);
+ }
+
+ private NotificationRecord getBuzzyOnceNotification() {
+ return getNotificationRecord(mId, false /* insistent */, true /* once */,
+ false /* noisy */, true /* buzzy*/);
+ }
+
+ private NotificationRecord getInsistentBuzzyNotification() {
+ return getNotificationRecord(mId, true /* insistent */, false /* once */,
+ false /* noisy */, true /* buzzy*/);
+ }
+
+ private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once,
+ boolean noisy, boolean buzzy) {
+ final Builder builder = new Builder(getContext())
+ .setContentTitle("foo")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .setPriority(Notification.PRIORITY_HIGH)
+ .setOnlyAlertOnce(once);
+
+ int defaults = 0;
+ if (noisy) {
+ defaults |= Notification.DEFAULT_SOUND;
+ }
+ if (buzzy) {
+ defaults |= Notification.DEFAULT_VIBRATE;
+ }
+ builder.setDefaults(defaults);
+
+ Notification n = builder.build();
+ if (insistent) {
+ n.flags |= Notification.FLAG_INSISTENT;
+ }
+ StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid, mPid,
+ mScore, n, mUser, System.currentTimeMillis());
+ return new NotificationRecord(getContext(), sbn);
+ }
+
+ //
+ // Convenience functions for interacting with mocks
+ //
+
+ private void verifyNeverBeep() throws RemoteException {
+ verify(mRingtonePlayer, never()).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
+ anyBoolean(), (AudioAttributes) anyObject());
+ }
+
+ private void verifyBeep() throws RemoteException {
+ verify(mRingtonePlayer, times(1)).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
+ eq(true), (AudioAttributes) anyObject());
+ }
+
+ private void verifyBeepLooped() throws RemoteException {
+ verify(mRingtonePlayer, times(1)).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
+ eq(false), (AudioAttributes) anyObject());
+ }
+
+ private void verifyNeverStopAudio() throws RemoteException {
+ verify(mRingtonePlayer, never()).stopAsync();
+ }
+
+ private void verifyStopAudio() throws RemoteException {
+ verify(mRingtonePlayer, times(1)).stopAsync();
+ }
+
+ private void verifyNeverVibrate() {
+ verify(mVibrator, never()).vibrate(anyInt(), anyString(), (long[]) anyObject(),
+ anyInt(), (AudioAttributes) anyObject());
+ }
+
+ private void verifyVibrate() {
+ verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), (long[]) anyObject(),
+ eq(-1), (AudioAttributes) anyObject());
+ }
+
+ private void verifyVibrateLooped() {
+ verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), (long[]) anyObject(),
+ eq(0), (AudioAttributes) anyObject());
+ }
+
+ private void verifyStopVibrate() {
+ verify(mVibrator, times(1)).cancel();
+ }
+
+ private void verifyNeverStopVibrate() throws RemoteException {
+ verify(mVibrator, never()).cancel();
+ }
+
+ @SmallTest
+ public void testBeep() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyBeepLooped();
+ verifyNeverVibrate();
+ }
+
+ //
+ // Tests
+ //
+
+ @SmallTest
+ public void testBeepInsistently() throws Exception {
+ NotificationRecord r = getInsistentBeepyNotification();
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyBeep();
+ }
+
+ @SmallTest
+ public void testNoInterruptionForMin() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ r.setImportance(Ranking.IMPORTANCE_MIN, "foo");
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyNeverBeep();
+ verifyNeverVibrate();
+ }
+
+ @SmallTest
+ public void testNoInterruptionForIntercepted() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ r.setIntercepted(true);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyNeverBeep();
+ verifyNeverVibrate();
+ }
+
+ @SmallTest
+ public void testBeepTwice() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+ Mockito.reset(mRingtonePlayer);
+
+ // update should beep
+ r.isUpdate = true;
+ mService.buzzBeepBlinkLocked(r);
+ verifyBeepLooped();
+ }
+
+ @SmallTest
+ public void testHonorAlertOnlyOnceForBeep() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ NotificationRecord s = getBeepyOnceNotification();
+ s.isUpdate = true;
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+ Mockito.reset(mRingtonePlayer);
+
+ // update should not beep
+ mService.buzzBeepBlinkLocked(s);
+ verifyNeverBeep();
+ }
+
+ @SmallTest
+ public void testNoisyUpdateDoesNotCancelAudio() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+
+ mService.buzzBeepBlinkLocked(r);
+ r.isUpdate = true;
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyNeverStopAudio();
+ }
+
+ @SmallTest
+ public void testNoisyOnceUpdateDoesNotCancelAudio() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ NotificationRecord s = getBeepyOnceNotification();
+ s.isUpdate = true;
+
+ mService.buzzBeepBlinkLocked(r);
+ mService.buzzBeepBlinkLocked(s);
+
+ verifyNeverStopAudio();
+ }
+
+ @SmallTest
+ public void testQuietUpdateDoesNotCancelAudioFromOther() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ NotificationRecord s = getQuietNotification();
+ s.isUpdate = true;
+ NotificationRecord other = getNoisyOtherNotification();
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+ mService.buzzBeepBlinkLocked(other); // this takes the audio stream
+ Mockito.reset(mRingtonePlayer);
+
+ // should not stop noise, since we no longer own it
+ mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
+ verifyNeverStopAudio();
+ }
+
+ @SmallTest
+ public void testQuietInterloperDoesNotCancelAudio() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ NotificationRecord other = getQuietOtherNotification();
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+ Mockito.reset(mRingtonePlayer);
+
+ // should not stop noise, since it does not own it
+ mService.buzzBeepBlinkLocked(other);
+ verifyNeverStopAudio();
+ }
+
+ @SmallTest
+ public void testQuietUpdateCancelsAudio() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ NotificationRecord s = getQuietNotification();
+ s.isUpdate = true;
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+ Mockito.reset(mRingtonePlayer);
+
+ // quiet update should stop making noise
+ mService.buzzBeepBlinkLocked(s);
+ verifyStopAudio();
+ }
+
+ @SmallTest
+ public void testQuietOnceUpdateCancelsAudio() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ NotificationRecord s = getQuietOnceNotification();
+ s.isUpdate = true;
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+ Mockito.reset(mRingtonePlayer);
+
+ // stop making noise - this is a weird corner case, but quiet should override once
+ mService.buzzBeepBlinkLocked(s);
+ verifyStopAudio();
+ }
+
+ @SmallTest
+ public void testDemoteSoundToVibrate() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+
+ // the phone is quiet
+ when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyNeverBeep();
+ verifyVibrate();
+ }
+
+ @SmallTest
+ public void testDemotInsistenteSoundToVibrate() throws Exception {
+ NotificationRecord r = getInsistentBeepyNotification();
+
+ // the phone is quiet
+ when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyVibrateLooped();
+ }
+
+ @SmallTest
+ public void testVibrate() throws Exception {
+ NotificationRecord r = getBuzzyNotification();
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyNeverBeep();
+ verifyVibrate();
+ }
+
+ @SmallTest
+ public void testInsistenteVibrate() throws Exception {
+ NotificationRecord r = getInsistentBuzzyNotification();
+
+ mService.buzzBeepBlinkLocked(r);
+ verifyVibrateLooped();
+ }
+
+ @SmallTest
+ public void testVibratTwice() throws Exception {
+ NotificationRecord r = getBuzzyNotification();
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+ Mockito.reset(mVibrator);
+
+ // update should vibrate
+ r.isUpdate = true;
+ mService.buzzBeepBlinkLocked(r);
+ verifyVibrate();
+ }
+
+ @SmallTest
+ public void testHonorAlertOnlyOnceForBuzz() throws Exception {
+ NotificationRecord r = getBuzzyNotification();
+ NotificationRecord s = getBuzzyOnceNotification();
+ s.isUpdate = true;
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+ Mockito.reset(mVibrator);
+
+ // update should not beep
+ mService.buzzBeepBlinkLocked(s);
+ verifyNeverVibrate();
+ }
+
+ @SmallTest
+ public void testNoisyUpdateDoesNotCancelVibrate() throws Exception {
+ NotificationRecord r = getBuzzyNotification();
+
+ mService.buzzBeepBlinkLocked(r);
+ r.isUpdate = true;
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyNeverStopVibrate();
+ }
+
+ @SmallTest
+ public void testNoisyOnceUpdateDoesNotCancelVibrate() throws Exception {
+ NotificationRecord r = getBuzzyNotification();
+ NotificationRecord s = getBuzzyOnceNotification();
+ s.isUpdate = true;
+
+ mService.buzzBeepBlinkLocked(r);
+ mService.buzzBeepBlinkLocked(s);
+
+ verifyNeverStopVibrate();
+ }
+
+ @SmallTest
+ public void testQuietUpdateDoesNotCancelVibrateFromOther() throws Exception {
+ NotificationRecord r = getBuzzyNotification();
+ NotificationRecord s = getQuietNotification();
+ s.isUpdate = true;
+ NotificationRecord other = getNoisyOtherNotification();
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+ mService.buzzBeepBlinkLocked(other); // this takes the vibrate stream
+ Mockito.reset(mVibrator);
+
+ // should not stop vibrate, since we no longer own it
+ mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
+ verifyNeverStopVibrate();
+ }
+
+ @SmallTest
+ public void testQuietInterloperDoesNotCancelVibrate() throws Exception {
+ NotificationRecord r = getBuzzyNotification();
+ NotificationRecord other = getQuietOtherNotification();
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+ Mockito.reset(mVibrator);
+
+ // should not stop noise, since it does not own it
+ mService.buzzBeepBlinkLocked(other);
+ verifyNeverStopVibrate();
+ }
+
+ @SmallTest
+ public void testQuietUpdateCancelsVibrate() throws Exception {
+ NotificationRecord r = getBuzzyNotification();
+ NotificationRecord s = getQuietNotification();
+ s.isUpdate = true;
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+
+ // quiet update should stop making noise
+ mService.buzzBeepBlinkLocked(s);
+ verifyStopVibrate();
+ }
+
+ @SmallTest
+ public void testQuietOnceUpdateCancelsvibrate() throws Exception {
+ NotificationRecord r = getBuzzyNotification();
+ NotificationRecord s = getQuietOnceNotification();
+ s.isUpdate = true;
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+ Mockito.reset(mVibrator);
+
+ // stop making noise - this is a weird corner case, but quiet should override once
+ mService.buzzBeepBlinkLocked(s);
+ verifyStopVibrate();
+ }
+
+ @SmallTest
+ public void testQuietUpdateCancelsDemotedVibrate() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ NotificationRecord s = getQuietNotification();
+
+ // the phone is quiet
+ when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ // quiet update should stop making noise
+ mService.buzzBeepBlinkLocked(s);
+ verifyStopVibrate();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutInfoTest.java
deleted file mode 100644
index c44ffa4..0000000
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutInfoTest.java
+++ /dev/null
@@ -1,271 +0,0 @@
-
-/*
- * Copyright (C) 2016 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.pm;
-
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.pm.ShortcutInfo;
-import android.graphics.drawable.Icon;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.PersistableBundle;
-import android.test.AndroidTestCase;
-
-import com.android.internal.util.Preconditions;
-import com.android.server.testutis.TestUtils;
-
-/**
- * Tests for {@link ShortcutInfo}.
-
- m FrameworksServicesTests &&
- adb install \
- -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
- adb shell am instrument -e class com.android.server.pm.ShortcutInfoTest \
- -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
-
- */
-public class ShortcutInfoTest extends AndroidTestCase {
-
- public void testMissingMandatoryFields() {
- TestUtils.assertExpectException(
- IllegalArgumentException.class,
- "ID must be provided",
- () -> new ShortcutInfo.Builder(mContext).build());
- TestUtils.assertExpectException(
- IllegalArgumentException.class,
- "title must be provided",
- () -> new ShortcutInfo.Builder(mContext).setId("id").build()
- .enforceMandatoryFields());
- TestUtils.assertExpectException(
- NullPointerException.class,
- "Intent must be provided",
- () -> new ShortcutInfo.Builder(mContext).setId("id").setTitle("x").build()
- .enforceMandatoryFields());
- }
-
- private ShortcutInfo parceled(ShortcutInfo si) {
- Parcel p = Parcel.obtain();
- p.writeParcelable(si, 0);
- p.setDataPosition(0);
- ShortcutInfo si2 = p.readParcelable(getClass().getClassLoader());
- p.recycle();
- return si2;
- }
-
- private Intent makeIntent(String action, Object... bundleKeysAndValues) {
- final Intent intent = new Intent(action);
- intent.replaceExtras(ShortcutManagerTest.makeBundle(bundleKeysAndValues));
- return intent;
- }
-
- public void testParcel() {
- ShortcutInfo si = parceled(new ShortcutInfo.Builder(getContext())
- .setId("id")
- .setTitle("title")
- .setIntent(makeIntent("action"))
- .build());
- assertEquals(getContext().getPackageName(), si.getPackageName());
- assertEquals("id", si.getId());
- assertEquals("title", si.getTitle());
- assertEquals("action", si.getIntent().getAction());
-
- PersistableBundle pb = new PersistableBundle();
- pb.putInt("k", 1);
-
- si = new ShortcutInfo.Builder(getContext())
- .setId("id")
- .setActivityComponent(new ComponentName("a", "b"))
- .setIcon(Icon.createWithContentUri("content://a.b.c/"))
- .setTitle("title")
- .setText("text")
- .setIntent(makeIntent("action", "key", "val"))
- .setWeight(123)
- .setExtras(pb)
- .build();
- si.addFlags(ShortcutInfo.FLAG_PINNED);
- si.setBitmapPath("abc");
- si.setIconResourceId(456);
-
- si = parceled(si);
-
- assertEquals(getContext().getPackageName(), si.getPackageName());
- assertEquals("id", si.getId());
- assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
- assertEquals("content://a.b.c/", si.getIcon().getUriString());
- assertEquals("title", si.getTitle());
- assertEquals("text", si.getText());
- assertEquals("action", si.getIntent().getAction());
- assertEquals("val", si.getIntent().getStringExtra("key"));
- assertEquals(123, si.getWeight());
- assertEquals(1, si.getExtras().getInt("k"));
-
- assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
- assertEquals("abc", si.getBitmapPath());
- assertEquals(456, si.getIconResourceId());
- }
-
- public void testClone() {
- PersistableBundle pb = new PersistableBundle();
- pb.putInt("k", 1);
- ShortcutInfo sorig = new ShortcutInfo.Builder(getContext())
- .setId("id")
- .setActivityComponent(new ComponentName("a", "b"))
- .setIcon(Icon.createWithContentUri("content://a.b.c/"))
- .setTitle("title")
- .setText("text")
- .setIntent(makeIntent("action", "key", "val"))
- .setWeight(123)
- .setExtras(pb)
- .build();
- sorig.addFlags(ShortcutInfo.FLAG_PINNED);
- sorig.setBitmapPath("abc");
- sorig.setIconResourceId(456);
-
- ShortcutInfo si = sorig.clone(/* clone flags*/ 0);
-
- assertEquals(getContext().getPackageName(), si.getPackageName());
- assertEquals("id", si.getId());
- assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
- assertEquals("content://a.b.c/", si.getIcon().getUriString());
- assertEquals("title", si.getTitle());
- assertEquals("text", si.getText());
- assertEquals("action", si.getIntent().getAction());
- assertEquals("val", si.getIntent().getStringExtra("key"));
- assertEquals(123, si.getWeight());
- assertEquals(1, si.getExtras().getInt("k"));
-
- assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
- assertEquals("abc", si.getBitmapPath());
- assertEquals(456, si.getIconResourceId());
-
- si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
-
- assertEquals(getContext().getPackageName(), si.getPackageName());
- assertEquals("id", si.getId());
- assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
- assertEquals(null, si.getIcon());
- assertEquals("title", si.getTitle());
- assertEquals("text", si.getText());
- assertEquals("action", si.getIntent().getAction());
- assertEquals("val", si.getIntent().getStringExtra("key"));
- assertEquals(123, si.getWeight());
- assertEquals(1, si.getExtras().getInt("k"));
-
- assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
- assertEquals(null, si.getBitmapPath());
- assertEquals(0, si.getIconResourceId());
-
- si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
-
- assertEquals(getContext().getPackageName(), si.getPackageName());
- assertEquals("id", si.getId());
- assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
- assertEquals(null, si.getIcon());
- assertEquals("title", si.getTitle());
- assertEquals("text", si.getText());
- assertEquals(null, si.getIntent());
- assertEquals(123, si.getWeight());
- assertEquals(1, si.getExtras().getInt("k"));
-
- assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
- assertEquals(null, si.getBitmapPath());
- assertEquals(0, si.getIconResourceId());
-
- si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
-
- assertEquals(getContext().getPackageName(), si.getPackageName());
- assertEquals("id", si.getId());
- assertEquals(null, si.getActivityComponent());
- assertEquals(null, si.getIcon());
- assertEquals(null, si.getTitle());
- assertEquals(null, si.getText());
- assertEquals(null, si.getIntent());
- assertEquals(0, si.getWeight());
- assertEquals(null, si.getExtras());
-
- assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY, si.getFlags());
- assertEquals(null, si.getBitmapPath());
- assertEquals(0, si.getIconResourceId());
- }
-
-
- public void testCopyNonNullFieldsFrom() {
- PersistableBundle pb = new PersistableBundle();
- pb.putInt("k", 1);
- ShortcutInfo sorig = new ShortcutInfo.Builder(getContext())
- .setId("id")
- .setActivityComponent(new ComponentName("a", "b"))
- .setIcon(Icon.createWithContentUri("content://a.b.c/"))
- .setTitle("title")
- .setText("text")
- .setIntent(makeIntent("action", "key", "val"))
- .setWeight(123)
- .setExtras(pb)
- .build();
- sorig.addFlags(ShortcutInfo.FLAG_PINNED);
- sorig.setBitmapPath("abc");
- sorig.setIconResourceId(456);
-
- ShortcutInfo si;
-
- si = sorig.clone(/* flags=*/ 0);
- si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
- .setActivityComponent(new ComponentName("x", "y")).build());
- assertEquals(new ComponentName("x", "y"), si.getActivityComponent());
-
- si = sorig.clone(/* flags=*/ 0);
- si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
- .setIcon(Icon.createWithContentUri("content://x.y.z/")).build());
- assertEquals("content://x.y.z/", si.getIcon().getUriString());
-
- si = sorig.clone(/* flags=*/ 0);
- si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
- .setTitle("xyz").build());
- assertEquals("xyz", si.getTitle());
-
- si = sorig.clone(/* flags=*/ 0);
- si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
- .setText("xxx").build());
- assertEquals("xxx", si.getText());
-
- si = sorig.clone(/* flags=*/ 0);
- si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
- .setIntent(makeIntent("action2")).build());
- assertEquals("action2", si.getIntent().getAction());
- assertEquals(null, si.getIntent().getStringExtra("key"));
-
- si = sorig.clone(/* flags=*/ 0);
- si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
- .setIntent(makeIntent("action3", "key", "x")).build());
- assertEquals("action3", si.getIntent().getAction());
- assertEquals("x", si.getIntent().getStringExtra("key"));
-
- si = sorig.clone(/* flags=*/ 0);
- si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
- .setWeight(999).build());
- assertEquals(999, si.getWeight());
-
-
- PersistableBundle pb2 = new PersistableBundle();
- pb2.putInt("x", 99);
-
- si = sorig.clone(/* flags=*/ 0);
- si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
- .setExtras(pb2).build());
- assertEquals(99, si.getExtras().getInt("x"));
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
index 5d29242..baa5d36 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
@@ -16,8 +16,11 @@
package com.android.server.pm;
import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyList;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
@@ -46,6 +49,7 @@
import android.content.pm.ShortcutManager;
import android.content.pm.ShortcutServiceInternal;
import android.content.pm.Signature;
+import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
@@ -57,7 +61,9 @@
import android.os.FileUtils;
import android.os.Handler;
import android.os.Looper;
+import android.os.Parcel;
import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
@@ -66,6 +72,7 @@
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Pair;
import android.util.SparseArray;
import com.android.frameworks.servicestests.R;
@@ -76,6 +83,7 @@
import com.android.server.pm.ShortcutService.ConfigConstants;
import com.android.server.pm.ShortcutService.FileOutputStreamWithPath;
import com.android.server.pm.ShortcutUser.PackageWithUser;
+import com.android.server.testutis.TestUtils;
import libcore.io.IoUtils;
@@ -96,6 +104,8 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
/**
* Tests for ShortcutService and ShortcutManager.
@@ -107,10 +117,8 @@
-w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
* TODO: Add checks with assertAllNotHaveIcon()
- *
- * TODO: separate, detailed tests for ShortcutInfo (CTS?) *
- *
- * TODO: Cross-user test (do in CTS?)
+ * TODO: Detailed test for hasShortcutPermissionInner().
+ * TODO: Add tests for the command line functions too.
*/
@SmallTest
public class ShortcutManagerTest extends InstrumentationTestCase {
@@ -122,6 +130,8 @@
*/
private static final boolean ENABLE_DUMP = false; // DO NOT SUBMIT WITH true
+ private static final boolean DUMP_IN_TEARDOWN = false; // DO NOT SUBMIT WITH true
+
// public for mockito
public class BaseContext extends MockContext {
@Override
@@ -260,8 +270,7 @@
@Override
boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId) {
- // Sort of hack; do a simpler check.
- return LAUNCHER_1.equals(callingPackage) || LAUNCHER_2.equals(callingPackage);
+ return mDefaultLauncherChecker.test(callingPackage, userId);
}
@Override
@@ -279,12 +288,7 @@
@Override
void postToHandler(Runnable r) {
final long token = mContext.injectClearCallingIdentity();
- super.postToHandler(r);
- try {
- runTestOnUiThread(() -> {});
- } catch (Throwable e) {
- fail("runTestOnUiThread failed: " + e);
- }
+ r.run();
mContext.injectRestoreCallingIdentity(token);
}
@@ -316,36 +320,11 @@
}
@Override
- public void ensureInUserProfiles(UserHandle userToCheck, String message) {
- if (getCallingUserId() == userToCheck.getIdentifier()) {
- return; // okay
- }
- if (getCallingUserId() == USER_0 && userToCheck.getIdentifier() == USER_P0) {
- return; // profile, okay.
- }
- if (getCallingUserId() == USER_P0 && userToCheck.getIdentifier() == USER_0) {
- return; // profile, okay.
- }
-
- if (mInjectedCallingUid != Process.SYSTEM_UID) {
- throw new SecurityException("To access other users, you need to be SYSTEM" +
- ", but current UID=" + mInjectedCallingUid);
- }
- }
-
- @Override
public void verifyCallingPackage(String callingPackage) {
// SKIP
}
@Override
- boolean isEnabledProfileOf(UserHandle user, UserHandle listeningUser, String debugMsg) {
- // This requires CROSS_USER
- assertEquals(Process.SYSTEM_UID, mInjectedCallingUid);
- return user.getIdentifier() == listeningUser.getIdentifier();
- }
-
- @Override
void postToPackageMonitorHandler(Runnable r) {
final long token = mContext.injectClearCallingIdentity();
r.run();
@@ -356,6 +335,18 @@
int injectBinderCallingUid() {
return mInjectedCallingUid;
}
+
+ @Override
+ long injectClearCallingIdentity() {
+ final int prevCallingUid = mInjectedCallingUid;
+ mInjectedCallingUid = Process.SYSTEM_UID;
+ return prevCallingUid;
+ }
+
+ @Override
+ void injectRestoreCallingIdentity(long token) {
+ mInjectedCallingUid = (int) token;
+ }
}
private class LauncherAppsTestable extends LauncherApps {
@@ -381,7 +372,11 @@
private ShortcutServiceInternal mInternal;
private LauncherAppImplTestable mLauncherAppImpl;
- private LauncherAppsTestable mLauncherApps;
+
+ // LauncherApps has per-instace state, so we need a differnt instance for each launcher.
+ private final Map<Pair<Integer, String>, LauncherAppsTestable>
+ mLauncherAppsMap = new HashMap<>();
+ private LauncherAppsTestable mLauncherApps; // Current one
private File mInjectedFilePathRoot;
@@ -394,7 +389,7 @@
private Map<String, PackageInfo> mInjectedPackages;
- private ArrayList<PackageWithUser> mUninstalledPackages;
+ private Set<PackageWithUser> mUninstalledPackages;
private PackageManager mMockPackageManager;
private PackageManagerInternal mMockPackageManagerInternal;
@@ -409,12 +404,21 @@
private static final String CALLING_PACKAGE_3 = "com.android.test.3";
private static final int CALLING_UID_3 = 10003;
+ private static final String CALLING_PACKAGE_4 = "com.android.test.4";
+ private static final int CALLING_UID_4 = 10004;
+
private static final String LAUNCHER_1 = "com.android.launcher.1";
private static final int LAUNCHER_UID_1 = 10011;
private static final String LAUNCHER_2 = "com.android.launcher.2";
private static final int LAUNCHER_UID_2 = 10012;
+ private static final String LAUNCHER_3 = "com.android.launcher.3";
+ private static final int LAUNCHER_UID_3 = 10013;
+
+ private static final String LAUNCHER_4 = "com.android.launcher.4";
+ private static final int LAUNCHER_UID_4 = 10014;
+
private static final int USER_0 = UserHandle.USER_SYSTEM;
private static final int USER_10 = 10;
private static final int USER_11 = 11;
@@ -425,6 +429,24 @@
private static final UserHandle HANDLE_USER_11 = UserHandle.of(USER_11);
private static final UserHandle HANDLE_USER_P0 = UserHandle.of(USER_P0);
+ private static final UserInfo USER_INFO_0 = withProfileGroupId(
+ new UserInfo(USER_0, "user0",
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED), 10);
+
+ private static final UserInfo USER_INFO_10 =
+ new UserInfo(USER_10, "user10", UserInfo.FLAG_INITIALIZED);
+
+ private static final UserInfo USER_INFO_11 =
+ new UserInfo(USER_11, "user11", UserInfo.FLAG_INITIALIZED);
+
+ private static final UserInfo USER_INFO_P0 = withProfileGroupId(
+ new UserInfo(USER_P0, "userP0",
+ UserInfo.FLAG_MANAGED_PROFILE), 10);
+
+ private BiPredicate<String, Integer> mDefaultLauncherChecker =
+ (callingPackage, userId) ->
+ LAUNCHER_1.equals(callingPackage) || LAUNCHER_2.equals(callingPackage)
+ || LAUNCHER_3.equals(callingPackage) || LAUNCHER_4.equals(callingPackage);
private static final long START_TIME = 1440000000101L;
@@ -438,6 +460,13 @@
private static final int MAX_ICON_DIMENSION_LOWRAM = 32;
+ private static final ShortcutQuery QUERY_ALL = new ShortcutQuery();
+
+ static {
+ QUERY_ALL.setQueryFlags(
+ ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED);
+ }
+
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -457,30 +486,83 @@
addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 1);
addPackage(CALLING_PACKAGE_2, CALLING_UID_2, 2);
addPackage(CALLING_PACKAGE_3, CALLING_UID_3, 3);
+ addPackage(CALLING_PACKAGE_4, CALLING_UID_4, 10);
addPackage(LAUNCHER_1, LAUNCHER_UID_1, 4);
addPackage(LAUNCHER_2, LAUNCHER_UID_2, 5);
+ addPackage(LAUNCHER_3, LAUNCHER_UID_3, 6);
+ addPackage(LAUNCHER_4, LAUNCHER_UID_4, 10);
- mUninstalledPackages = new ArrayList<>();
+ // CALLING_PACKAGE_3 / LAUNCHER_3 are not backup target.
+ updatePackageInfo(CALLING_PACKAGE_3,
+ pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+ updatePackageInfo(LAUNCHER_3,
+ pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+ mUninstalledPackages = new HashSet<>();
mInjectedFilePathRoot = new File(getTestContext().getCacheDir(), "test-files");
- // Empty the data directory.
- if (mInjectedFilePathRoot.exists()) {
- Assert.assertTrue("failed to delete dir",
- FileUtils.deleteContents(mInjectedFilePathRoot));
- }
- mInjectedFilePathRoot.mkdirs();
+ deleteAllSavedFiles();
+
+ // Set up users.
+ doAnswer(inv -> {
+ assertSystem();
+ return USER_INFO_0;
+ }).when(mMockUserManager).getUserInfo(eq(USER_0));
+
+ doAnswer(inv -> {
+ assertSystem();
+ return USER_INFO_10;
+ }).when(mMockUserManager).getUserInfo(eq(USER_10));
+
+ doAnswer(inv -> {
+ assertSystem();
+ return USER_INFO_11;
+ }).when(mMockUserManager).getUserInfo(eq(USER_11));
+
+ doAnswer(inv -> {
+ assertSystem();
+ return USER_INFO_P0;
+ }).when(mMockUserManager).getUserInfo(eq(USER_P0));
+
+ // User 0 is always running.
+ when(mMockUserManager.isUserRunning(eq(USER_0))).thenReturn(true);
initService();
setCaller(CALLING_PACKAGE_1);
}
+ private static UserInfo withProfileGroupId(UserInfo in, int groupId) {
+ in.profileGroupId = groupId;
+ return in;
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ if (DUMP_IN_TEARDOWN) dumpsysOnLogcat("Teardown");
+
+ shutdownServices();
+
+ super.tearDown();
+ }
+
private Context getTestContext() {
return getInstrumentation().getContext();
}
+ private void deleteAllSavedFiles() {
+ // Empty the data directory.
+ if (mInjectedFilePathRoot.exists()) {
+ Assert.assertTrue("failed to delete dir",
+ FileUtils.deleteContents(mInjectedFilePathRoot));
+ }
+ mInjectedFilePathRoot.mkdirs();
+ }
+
/** (Re-) init the manager and the service. */
private void initService() {
+ shutdownServices();
+
LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
// Instantiate targets.
@@ -490,12 +572,28 @@
mInternal = LocalServices.getService(ShortcutServiceInternal.class);
mLauncherAppImpl = new LauncherAppImplTestable(mServiceContext);
- mLauncherApps = new LauncherAppsTestable(mClientContext, mLauncherAppImpl);
+ mLauncherApps = null;
+ mLauncherAppsMap.clear();
// Load the setting file.
mService.onBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY);
}
+ private void shutdownServices() {
+ if (mService != null) {
+ // Flush all the unsaved data from the previous instance.
+ mService.saveDirtyInfo();
+ }
+ LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
+
+ mService = null;
+ mManager = null;
+ mInternal = null;
+ mLauncherAppImpl = null;
+ mLauncherApps = null;
+ mLauncherAppsMap.clear();
+ }
+
private void addPackage(String packageName, int uid, int version) {
addPackage(packageName, uid, version, packageName);
}
@@ -504,6 +602,10 @@
return Arrays.asList(array);
}
+ private <T> Set<T> set(Set<T> in) {
+ return new ArraySet<T>(in);
+ }
+
private Signature[] genSignatures(String... signatures) {
final Signature[] sigs = new Signature[signatures.length];
for (int i = 0; i < signatures.length; i++){
@@ -529,10 +631,24 @@
mInjectedPackages.put(packageName, genPackage(packageName, uid, version, signatures));
}
+ private void updatePackageInfo(String packageName, Consumer<PackageInfo> c) {
+ c.accept(mInjectedPackages.get(packageName));
+ }
+
private void uninstallPackage(int userId, String packageName) {
+ if (ENABLE_DUMP) {
+ Log.i(TAG, "Unnstall package " + packageName + " / " + userId);
+ }
mUninstalledPackages.add(PackageWithUser.of(userId, packageName));
}
+ private void installPackage(int userId, String packageName) {
+ if (ENABLE_DUMP) {
+ Log.i(TAG, "Install package " + packageName + " / " + userId);
+ }
+ mUninstalledPackages.remove(PackageWithUser.of(userId, packageName));
+ }
+
PackageInfo getInjectedPackageInfo(String packageName, @UserIdInt int userId,
boolean getSignatures) {
final PackageInfo pi = mInjectedPackages.get(packageName);
@@ -560,6 +676,13 @@
mInjectedCallingUid =
Preconditions.checkNotNull(getInjectedPackageInfo(packageName, userId, false),
"Unknown package").applicationInfo.uid;
+
+ // Set up LauncherApps for this caller.
+ final Pair<Integer, String> key = Pair.create(userId, packageName);
+ if (!mLauncherAppsMap.containsKey(key)) {
+ mLauncherAppsMap.put(key, new LauncherAppsTestable(mClientContext, mLauncherAppImpl));
+ }
+ mLauncherApps = mLauncherAppsMap.get(key);
}
private void setCaller(String packageName) {
@@ -570,6 +693,10 @@
return mInjectedClientPackage;
}
+ private void setDefaultLauncherChecker(BiPredicate<String, Integer> p) {
+ mDefaultLauncherChecker = p;
+ }
+
private void runWithCaller(String packageName, int userId, Runnable r) {
final String previousPackage = mInjectedClientPackage;
final int previousUserId = UserHandle.getUserId(mInjectedCallingUid);
@@ -591,14 +718,22 @@
/** For debugging */
private void dumpsysOnLogcat() {
- if (!ENABLE_DUMP) return;
+ dumpsysOnLogcat("");
+ }
+
+ private void dumpsysOnLogcat(String message) {
+ dumpsysOnLogcat(message, false);
+ }
+
+ private void dumpsysOnLogcat(String message, boolean force) {
+ if (force || !ENABLE_DUMP) return;
final ByteArrayOutputStream out = new ByteArrayOutputStream();
final PrintWriter pw = new PrintWriter(out);
mService.dumpInner(pw);
pw.close();
- Log.e(TAG, "Dumping ShortcutService:");
+ Log.e(TAG, "Dumping ShortcutService: " + message);
for (String line : out.toString().split("\n")) {
Log.e(TAG, line);
}
@@ -608,9 +743,13 @@
* For debugging, dump arbitrary file on logcat.
*/
private void dumpFileOnLogcat(String path) {
+ dumpFileOnLogcat(path, "");
+ }
+
+ private void dumpFileOnLogcat(String path, String message) {
if (!ENABLE_DUMP) return;
- Log.i(TAG, "Dumping file: " + path);
+ Log.i(TAG, "Dumping file: " + path + " " + message);
final StringBuilder sb = new StringBuilder();
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
String line;
@@ -636,10 +775,14 @@
* For debugging, dump per-user state file on logcat.
*/
private void dumpUserFile(int userId) {
+ dumpUserFile(userId, "");
+ }
+
+ private void dumpUserFile(int userId, String message) {
mService.saveDirtyInfo();
dumpFileOnLogcat(mInjectedFilePathRoot.getAbsolutePath()
+ "/user-" + userId
- + "/" + ShortcutService.FILENAME_USER_PACKAGES);
+ + "/" + ShortcutService.FILENAME_USER_PACKAGES, message);
}
private void waitOnMainThread() throws Throwable {
@@ -778,6 +921,12 @@
return ret;
}
+ private static void resetAll(Collection<?> mocks) {
+ for (Object o : mocks) {
+ reset(o);
+ }
+ }
+
@NonNull
private ShortcutInfo findById(List<ShortcutInfo> list, String id) {
for (ShortcutInfo s : list) {
@@ -789,6 +938,10 @@
return null;
}
+ private void assertSystem() {
+ assertEquals("Caller must be system", Process.SYSTEM_UID, mInjectedCallingUid);
+ }
+
private void assertResetTimes(long expectedLastResetTime, long expectedNextResetTime) {
assertEquals(expectedLastResetTime, mService.getLastResetTimeLocked());
assertEquals(expectedNextResetTime, mService.getNextResetTimeLocked());
@@ -877,7 +1030,7 @@
private List<ShortcutInfo> assertAllHaveIcon(
@NonNull List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
- assertTrue("ID " + s.getId(), s.hasIconFile() || s.hasIconResource());
+ assertTrue("ID " + s.getId() + " has no icon ", s.hasIconFile() || s.hasIconResource());
}
return actualShortcuts;
}
@@ -886,7 +1039,8 @@
private List<ShortcutInfo> assertAllHaveFlags(@NonNull List<ShortcutInfo> actualShortcuts,
int shortcutFlags) {
for (ShortcutInfo s : actualShortcuts) {
- assertTrue("ID " + s.getId(), s.hasFlags(shortcutFlags));
+ assertTrue("ID " + s.getId() + " doesn't have flags " + shortcutFlags,
+ s.hasFlags(shortcutFlags));
}
return actualShortcuts;
}
@@ -1055,11 +1209,13 @@
return i;
}
- /**
- * Wrap a set in an ArraySet just to get a better toString.
- */
- private <T> Set<T> set(Set<T> in) {
- return new ArraySet<T>(in);
+ private ShortcutInfo parceled(ShortcutInfo si) {
+ Parcel p = Parcel.obtain();
+ p.writeParcelable(si, 0);
+ p.setDataPosition(0);
+ ShortcutInfo si2 = p.readParcelable(getClass().getClassLoader());
+ p.recycle();
+ return si2;
}
/**
@@ -1320,8 +1476,6 @@
// Still 2 calls left.
assertEquals(2, mManager.getRemainingCallCount());
-
- // TODO Make sure pinned shortcuts won't be deleted.
}
public void testDeleteAllDynamicShortcuts() {
@@ -1351,8 +1505,6 @@
// Still 1 call left
assertEquals(1, mManager.getRemainingCallCount());
-
- // TODO Make sure pinned shortcuts won't be deleted.
}
public void testThrottling() {
@@ -1877,9 +2029,6 @@
});
}
- // TODO: updateShortcuts()
- // TODO: getPinnedShortcuts()
-
// === Test for launcher side APIs ===
private static ShortcutQuery buildQuery(long changedSince,
@@ -1893,6 +2042,20 @@
return q;
}
+ private static ShortcutQuery buildAllQuery(String packageName) {
+ final ShortcutQuery q = new ShortcutQuery();
+ q.setPackage(packageName);
+ q.setQueryFlags(ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED);
+ return q;
+ }
+
+ private static ShortcutQuery buildPinnedQuery(String packageName) {
+ final ShortcutQuery q = new ShortcutQuery();
+ q.setPackage(packageName);
+ q.setQueryFlags(ShortcutQuery.FLAG_GET_PINNED);
+ return q;
+ }
+
public void testGetShortcuts() {
// Set up shortcuts.
@@ -2928,12 +3091,6 @@
}
public void testLauncherCallback() throws Throwable {
-
- // TODO Add "multi" version -- run the test with two launchers and make sure the callback
- // argument only contains the ones that are actually visible to each launcher.
-
- when(mMockUserManager.isUserRunning(eq(USER_0))).thenReturn(true);
-
LauncherApps.Callback c0 = mock(LauncherApps.Callback.class);
// Set listeners
@@ -2989,6 +3146,7 @@
// Test for addDynamicShortcut.
reset(c0);
runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+ dumpsysOnLogcat("before addDynamicShortcut");
assertTrue(mManager.addDynamicShortcut(makeShortcut("s4")));
});
@@ -3052,6 +3210,7 @@
// Remove CALLING_PACKAGE_2
reset(c0);
+ uninstallPackage(USER_0, CALLING_PACKAGE_2);
mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_0, USER_0);
// Should get a callback with an empty list.
@@ -3065,6 +3224,156 @@
assertEquals(0, shortcuts.getValue().size());
}
+ private void assertCallbackNotReceived(LauncherApps.Callback mock) {
+ verify(mock, times(0)).onShortcutsChanged(anyString(), anyList(),
+ any(UserHandle.class));
+ }
+
+ private void assertCallbackReceived(LauncherApps.Callback mock,
+ UserHandle user, String packageName, String... ids) {
+ ArgumentCaptor<List> shortcutsCaptor = ArgumentCaptor.forClass(List.class);
+
+ verify(mock, times(1)).onShortcutsChanged(eq(packageName), shortcutsCaptor.capture(),
+ eq(user));
+ assertShortcutIds(shortcutsCaptor.getValue(), ids);
+ }
+
+ public void testLauncherCallback_crossProfile() throws Throwable {
+ prepareCrossProfileDataSet();
+
+ final Handler h = new Handler(Looper.getMainLooper());
+
+ final LauncherApps.Callback c0_1 = mock(LauncherApps.Callback.class);
+ final LauncherApps.Callback c0_2 = mock(LauncherApps.Callback.class);
+ final LauncherApps.Callback c0_3 = mock(LauncherApps.Callback.class);
+ final LauncherApps.Callback c0_4 = mock(LauncherApps.Callback.class);
+
+ final LauncherApps.Callback cP0_1 = mock(LauncherApps.Callback.class);
+ final LauncherApps.Callback c10_1 = mock(LauncherApps.Callback.class);
+ final LauncherApps.Callback c10_2 = mock(LauncherApps.Callback.class);
+ final LauncherApps.Callback c11_1 = mock(LauncherApps.Callback.class);
+
+ final List<LauncherApps.Callback> all =
+ list(c0_1, c0_2, c0_3, c0_4, cP0_1, c10_1, c11_1);
+
+ setDefaultLauncherChecker((pkg, userId) -> {
+ switch (userId) {
+ case USER_0:
+ return LAUNCHER_2.equals(pkg);
+ case USER_P0:
+ return LAUNCHER_1.equals(pkg);
+ case USER_10:
+ return LAUNCHER_1.equals(pkg);
+ case USER_11:
+ return LAUNCHER_1.equals(pkg);
+ default:
+ return false;
+ }
+ });
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> mLauncherApps.registerCallback(c0_1, h));
+ runWithCaller(LAUNCHER_2, USER_0, () -> mLauncherApps.registerCallback(c0_2, h));
+ runWithCaller(LAUNCHER_3, USER_0, () -> mLauncherApps.registerCallback(c0_3, h));
+ runWithCaller(LAUNCHER_4, USER_0, () -> mLauncherApps.registerCallback(c0_4, h));
+ runWithCaller(LAUNCHER_1, USER_P0, () -> mLauncherApps.registerCallback(cP0_1, h));
+ runWithCaller(LAUNCHER_1, USER_10, () -> mLauncherApps.registerCallback(c10_1, h));
+ runWithCaller(LAUNCHER_2, USER_10, () -> mLauncherApps.registerCallback(c10_2, h));
+ runWithCaller(LAUNCHER_1, USER_11, () -> mLauncherApps.registerCallback(c11_1, h));
+
+ // User 0.
+
+ resetAll(all);
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.deleteDynamicShortcut("x");
+ });
+ waitOnMainThread();
+
+ assertCallbackNotReceived(c0_1);
+ assertCallbackNotReceived(c0_3);
+ assertCallbackNotReceived(c0_4);
+ assertCallbackNotReceived(c10_1);
+ assertCallbackNotReceived(c10_2);
+ assertCallbackNotReceived(c11_1);
+ assertCallbackReceived(c0_2, HANDLE_USER_0, CALLING_PACKAGE_1, "s1", "s2", "s3");
+ assertCallbackReceived(cP0_1, HANDLE_USER_0, CALLING_PACKAGE_1, "s1", "s2", "s3", "s4");
+
+ // User 0, different package.
+
+ resetAll(all);
+ runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+ mManager.deleteDynamicShortcut("x");
+ });
+ waitOnMainThread();
+
+ assertCallbackNotReceived(c0_1);
+ assertCallbackNotReceived(c0_3);
+ assertCallbackNotReceived(c0_4);
+ assertCallbackNotReceived(c10_1);
+ assertCallbackNotReceived(c10_2);
+ assertCallbackNotReceived(c11_1);
+ assertCallbackReceived(c0_2, HANDLE_USER_0, CALLING_PACKAGE_3, "s1", "s2", "s3", "s4");
+ assertCallbackReceived(cP0_1, HANDLE_USER_0, CALLING_PACKAGE_3,
+ "s1", "s2", "s3", "s4", "s5", "s6");
+
+ // Work profile, but not running, so don't send notifications.
+
+ resetAll(all);
+ runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+ mManager.deleteDynamicShortcut("x");
+ });
+ waitOnMainThread();
+
+ assertCallbackNotReceived(c0_1);
+ assertCallbackNotReceived(c0_2);
+ assertCallbackNotReceived(c0_3);
+ assertCallbackNotReceived(c0_4);
+ assertCallbackNotReceived(cP0_1);
+ assertCallbackNotReceived(c10_1);
+ assertCallbackNotReceived(c10_2);
+ assertCallbackNotReceived(c11_1);
+
+ // Work profile, now running.
+
+ when(mMockUserManager.isUserRunning(anyInt())).thenReturn(false);
+ when(mMockUserManager.isUserRunning(eq(USER_P0))).thenReturn(true);
+
+ resetAll(all);
+ runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+ mManager.deleteDynamicShortcut("x");
+ });
+ waitOnMainThread();
+
+ assertCallbackNotReceived(c0_1);
+ assertCallbackNotReceived(c0_3);
+ assertCallbackNotReceived(c0_4);
+ assertCallbackNotReceived(c10_1);
+ assertCallbackNotReceived(c10_2);
+ assertCallbackNotReceived(c11_1);
+ assertCallbackReceived(c0_2, HANDLE_USER_P0, CALLING_PACKAGE_1, "s1", "s2", "s3", "s5");
+ assertCallbackReceived(cP0_1, HANDLE_USER_P0, CALLING_PACKAGE_1, "s1", "s2", "s3", "s4");
+
+ // Normal secondary user.
+
+ when(mMockUserManager.isUserRunning(anyInt())).thenReturn(false);
+ when(mMockUserManager.isUserRunning(eq(USER_10))).thenReturn(true);
+
+ resetAll(all);
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ mManager.deleteDynamicShortcut("x");
+ });
+ waitOnMainThread();
+
+ assertCallbackNotReceived(c0_1);
+ assertCallbackNotReceived(c0_2);
+ assertCallbackNotReceived(c0_3);
+ assertCallbackNotReceived(c0_4);
+ assertCallbackNotReceived(cP0_1);
+ assertCallbackNotReceived(c10_2);
+ assertCallbackNotReceived(c11_1);
+ assertCallbackReceived(c10_1, HANDLE_USER_10, CALLING_PACKAGE_1,
+ "x1", "x2", "x3", "x4", "x5");
+ }
+
// === Test for persisting ===
public void testSaveAndLoadUser_empty() {
@@ -3299,9 +3608,9 @@
// Check the registered packages.
dumpsysOnLogcat();
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
- set(user0.getPackages().keySet()));
+ set(user0.getAllPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
- set(user10.getPackages().keySet()));
+ set(user10.getAllPackages().keySet()));
assertEquals(
makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
PackageWithUser.of(USER_0, LAUNCHER_2)),
@@ -3326,13 +3635,14 @@
mService.saveDirtyInfo();
// Nonexistent package.
+ uninstallPackage(USER_0, "abc");
mService.cleanUpPackageLocked("abc", USER_0, USER_0);
// No changes.
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
- set(user0.getPackages().keySet()));
+ set(user0.getAllPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
- set(user10.getPackages().keySet()));
+ set(user10.getAllPackages().keySet()));
assertEquals(
makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
PackageWithUser.of(USER_0, LAUNCHER_2)),
@@ -3357,12 +3667,13 @@
mService.saveDirtyInfo();
// Remove a package.
+ uninstallPackage(USER_0, CALLING_PACKAGE_1);
mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_0, USER_0);
assertEquals(makeSet(CALLING_PACKAGE_2),
- set(user0.getPackages().keySet()));
+ set(user0.getAllPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
- set(user10.getPackages().keySet()));
+ set(user10.getAllPackages().keySet()));
assertEquals(
makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
PackageWithUser.of(USER_0, LAUNCHER_2)),
@@ -3387,12 +3698,13 @@
mService.saveDirtyInfo();
// Remove a launcher.
+ uninstallPackage(USER_10, LAUNCHER_1);
mService.cleanUpPackageLocked(LAUNCHER_1, USER_10, USER_10);
assertEquals(makeSet(CALLING_PACKAGE_2),
- set(user0.getPackages().keySet()));
+ set(user0.getAllPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
- set(user10.getPackages().keySet()));
+ set(user10.getAllPackages().keySet()));
assertEquals(
makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
PackageWithUser.of(USER_0, LAUNCHER_2)),
@@ -3414,12 +3726,13 @@
mService.saveDirtyInfo();
// Remove a package.
+ uninstallPackage(USER_10, CALLING_PACKAGE_2);
mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_10, USER_10);
assertEquals(makeSet(CALLING_PACKAGE_2),
- set(user0.getPackages().keySet()));
+ set(user0.getAllPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1),
- set(user10.getPackages().keySet()));
+ set(user10.getAllPackages().keySet()));
assertEquals(
makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
PackageWithUser.of(USER_0, LAUNCHER_2)),
@@ -3441,12 +3754,13 @@
mService.saveDirtyInfo();
// Remove the other launcher from user 10 too.
+ uninstallPackage(USER_10, LAUNCHER_2);
mService.cleanUpPackageLocked(LAUNCHER_2, USER_10, USER_10);
assertEquals(makeSet(CALLING_PACKAGE_2),
- set(user0.getPackages().keySet()));
+ set(user0.getAllPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1),
- set(user10.getPackages().keySet()));
+ set(user10.getAllPackages().keySet()));
assertEquals(
makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
PackageWithUser.of(USER_0, LAUNCHER_2)),
@@ -3468,12 +3782,13 @@
mService.saveDirtyInfo();
// More remove.
+ uninstallPackage(USER_10, CALLING_PACKAGE_1);
mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_10, USER_10);
assertEquals(makeSet(CALLING_PACKAGE_2),
- set(user0.getPackages().keySet()));
+ set(user0.getAllPackages().keySet()));
assertEquals(makeSet(),
- set(user10.getPackages().keySet()));
+ set(user10.getAllPackages().keySet()));
assertEquals(
makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
PackageWithUser.of(USER_0, LAUNCHER_2)),
@@ -3494,97 +3809,6 @@
mService.saveDirtyInfo();
}
-
- public void testSaveAndLoadUser_forBackup() {
- // Create some shortcuts.
- runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- assertTrue(mManager.setDynamicShortcuts(list(
- makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
- });
- runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
- assertTrue(mManager.setDynamicShortcuts(list(
- makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
- });
- runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
- assertTrue(mManager.setDynamicShortcuts(list(
- makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
- });
- runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
- assertTrue(mManager.setDynamicShortcuts(list(
- makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
- });
-
- assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
- assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
- assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
-
- assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
- assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
- assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
-
- assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
- assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
- assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
-
- assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
- assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
- assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
-
- // Pin some.
-
- runWithCaller(LAUNCHER_1, USER_0, () -> {
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
- list("s1"), HANDLE_USER_0);
-
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
- list("s2"), UserHandle.of(USER_P0));
-
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
- list("s3"), HANDLE_USER_0);
- });
-
- runWithCaller(LAUNCHER_1, USER_P0, () -> {
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
- list("s2"), HANDLE_USER_0);
-
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
- list("s3"), UserHandle.of(USER_P0));
-
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
- list("s1"), HANDLE_USER_0);
- });
-
- runWithCaller(LAUNCHER_1, USER_10, () -> {
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
- list("s3"), HANDLE_USER_10);
- });
-
- // Check the state.
-
- assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
- assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
- assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
-
- assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
- assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
- assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
-
- assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
- assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
- assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
-
- assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
- assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
- assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
-
- // Make sure all the information is persisted.
- mService.saveDirtyInfo();
- initService();
- mService.handleUnlockUser(USER_0);
- mService.handleUnlockUser(USER_P0);
- mService.handleUnlockUser(USER_10);
- }
-
public void testHandleGonePackage_crossProfile() {
// Create some shortcuts.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -3841,13 +4065,9 @@
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
}
- // TODO Detailed test for hasShortcutPermissionInner().
-
- // TODO Add tests for the command line functions too.
-
private void checkCanRestoreTo(boolean expected, ShortcutPackageInfo spi,
int version, String... signatures) {
- assertEquals(expected, spi.canRestoreTo(genPackage(
+ assertEquals(expected, spi.canRestoreTo(mService, genPackage(
"dummy", /* uid */ 0, version, signatures)));
}
@@ -3919,6 +4139,7 @@
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+ uninstallPackage(USER_0, CALLING_PACKAGE_1);
mService.mPackageMonitor.onReceive(getTestContext(),
genPackageDeleteIntent(CALLING_PACKAGE_1, USER_0));
@@ -3929,6 +4150,7 @@
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+ uninstallPackage(USER_10, CALLING_PACKAGE_2);
mService.mPackageMonitor.onReceive(getTestContext(),
genPackageDeleteIntent(CALLING_PACKAGE_2, USER_10));
@@ -3961,7 +4183,1193 @@
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
}
- public void testHandlePackageUpdate() {
- // TODO: Make sure unshadow is called.
+ private void backupAndRestore() {
+ int prevUid = mInjectedCallingUid;
+
+ mInjectedCallingUid = Process.SYSTEM_UID; // Only system can call it.
+
+ dumpsysOnLogcat("Before backup");
+
+ final byte[] payload = mService.getBackupPayload(USER_0);
+ if (ENABLE_DUMP) {
+ final String xml = new String(payload);
+ Log.i(TAG, "Backup payload:");
+ for (String line : xml.split("\n")) {
+ Log.i(TAG, line);
+ }
+ }
+
+ // Before doing anything else, uninstall all packages.
+ for (int userId : list(USER_0, USER_P0)) {
+ for (String pkg : list(CALLING_PACKAGE_1, CALLING_PACKAGE_2, CALLING_PACKAGE_3,
+ LAUNCHER_1, LAUNCHER_2, LAUNCHER_3)) {
+ uninstallPackage(userId, pkg);
+ }
+ }
+
+ shutdownServices();
+
+ deleteAllSavedFiles();
+
+ initService();
+ mService.applyRestore(payload, USER_0);
+
+ // handleUnlockUser will perform the gone package check, but it shouldn't remove
+ // shadow information.
+ mService.handleUnlockUser(USER_0);
+
+ dumpsysOnLogcat("After restore");
+
+ mInjectedCallingUid = prevUid;
+ }
+
+ private void prepareCrossProfileDataSet() {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+ makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+ });
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+ makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+ });
+ runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+ makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+ });
+ runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list()));
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+ makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3"),
+ makeShortcut("x4"), makeShortcut("x5"), makeShortcut("x6"))));
+ });
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s1", "s2"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s1", "s2", "s3"), HANDLE_USER_0);
+
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s4"), HANDLE_USER_P0);
+ });
+ runWithCaller(LAUNCHER_2, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s2", "s3"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s2", "s3", "s4"), HANDLE_USER_0);
+
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s5"), HANDLE_USER_P0);
+ });
+ runWithCaller(LAUNCHER_3, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5"), HANDLE_USER_0);
+
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s6"), HANDLE_USER_P0);
+ });
+ runWithCaller(LAUNCHER_4, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list(), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_4, list(), HANDLE_USER_0);
+ });
+
+ // Launcher on a managed profile is referring ot user 0!
+ runWithCaller(LAUNCHER_1, USER_P0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s4"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4", "s5"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5", "s6"),
+ HANDLE_USER_0);
+
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s4", "s1"), HANDLE_USER_P0);
+ });
+ runWithCaller(LAUNCHER_1, USER_10, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("x4", "x5"), HANDLE_USER_10);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("x4", "x5", "x6"), HANDLE_USER_10);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("x4", "x5", "x6", "x1"),
+ HANDLE_USER_10);
+ });
+
+ // Then remove some dynamic shortcuts.
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+ });
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+ });
+ runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+ });
+ runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list()));
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3"))));
+ });
+ }
+
+ private void prepareForBackupTest() {
+
+ prepareCrossProfileDataSet();
+
+ backupAndRestore();
+ }
+
+ private void assertExistsAndShadow(ShortcutPackageItem spi) {
+ assertNotNull(spi);
+ assertTrue(spi.getPackageInfo().isShadow());
+ }
+
+ /**
+ * Make sure the backup data doesn't have the following information:
+ * - Launchers on other users.
+ * - Non-backup app information.
+ *
+ * But restores all other infomation.
+ *
+ * It also omits the following pieces of information, but that's tested in
+ * {@link #testShortcutInfoSaveAndLoad_forBackup}.
+ * - Unpinned dynamic shortcuts
+ * - Bitmaps
+ */
+ public void testBackupAndRestore() {
+ prepareForBackupTest();
+
+ checkBackupAndRestore_success();
+ }
+
+ public void testBackupAndRestore_backupRestoreTwice() {
+ prepareForBackupTest();
+
+ // Note doing a backup & restore again here shouldn't affect the result.
+ dumpsysOnLogcat("Before second backup");
+
+ backupAndRestore();
+
+ dumpsysOnLogcat("After second backup");
+
+ checkBackupAndRestore_success();
+ }
+
+ public void testBackupAndRestore_backupRestoreMultiple() {
+ prepareForBackupTest();
+
+ // Note doing a backup & restore again here shouldn't affect the result.
+ backupAndRestore();
+
+ // This also shouldn't affect the result.
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+ makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+ });
+
+ backupAndRestore();
+
+ checkBackupAndRestore_success();
+ }
+
+ public void testBackupAndRestore_restoreToNewVersion() {
+ prepareForBackupTest();
+
+ // Note doing a backup & restore again here shouldn't affect the result.
+ backupAndRestore();
+
+ addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 2);
+ addPackage(LAUNCHER_1, LAUNCHER_UID_1, 5);
+
+ checkBackupAndRestore_success();
+ }
+
+ public void testBackupAndRestore_restoreToSuperSetSignatures() {
+ prepareForBackupTest();
+
+ // Note doing a backup & restore again here shouldn't affect the result.
+ backupAndRestore();
+
+ // Change package signatures.
+ addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 1, "sigx", CALLING_PACKAGE_1);
+ addPackage(LAUNCHER_1, LAUNCHER_UID_1, 4, LAUNCHER_1, "sigy");
+
+ checkBackupAndRestore_success();
+ }
+
+ private void checkBackupAndRestore_success() {
+ // Make sure non-system user is not restored.
+ final ShortcutUser userP0 = mService.getUserShortcutsLocked(USER_P0);
+ assertEquals(0, userP0.getAllPackages().size());
+ assertEquals(0, userP0.getAllLaunchers().size());
+
+ // Make sure only "allowBackup" apps are restored, and are shadow.
+ final ShortcutUser user0 = mService.getUserShortcutsLocked(USER_0);
+ assertExistsAndShadow(user0.getAllPackages().get(CALLING_PACKAGE_1));
+ assertExistsAndShadow(user0.getAllPackages().get(CALLING_PACKAGE_2));
+ assertExistsAndShadow(user0.getAllLaunchers().get(PackageWithUser.of(USER_0, LAUNCHER_1)));
+ assertExistsAndShadow(user0.getAllLaunchers().get(PackageWithUser.of(USER_0, LAUNCHER_2)));
+
+ assertNull(user0.getAllPackages().get(CALLING_PACKAGE_3));
+ assertNull(user0.getAllLaunchers().get(PackageWithUser.of(USER_0, LAUNCHER_3)));
+ assertNull(user0.getAllLaunchers().get(PackageWithUser.of(USER_P0, LAUNCHER_1)));
+
+ installPackage(USER_0, CALLING_PACKAGE_1);
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllPinned(
+ mManager.getPinnedShortcuts()),
+ "s1", "s2");
+ });
+
+ installPackage(USER_0, LAUNCHER_1);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+ "s1");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+ /* empty, not restored */ );
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty, not restored */ );
+
+ assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+ });
+
+ installPackage(USER_0, CALLING_PACKAGE_2);
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllPinned(
+ mManager.getPinnedShortcuts()),
+ "s1", "s2", "s3");
+ });
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+ "s1");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+ "s1", "s2");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty, not restored */ );
+
+ assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+ });
+
+ // 3 shouldn't be backed up, so no pinned shortcuts.
+ installPackage(USER_0, CALLING_PACKAGE_3);
+ runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertEquals(0, mManager.getPinnedShortcuts().size());
+ });
+
+ // Launcher on a different profile shouldn't be restored.
+ runWithCaller(LAUNCHER_1, USER_P0, () -> {
+ assertEquals(0,
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)
+ .size());
+ assertEquals(0,
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)
+ .size());
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* wasn't restored, so still empty */ );
+ });
+
+ // Package on a different profile, no restore.
+ installPackage(USER_P0, CALLING_PACKAGE_1);
+ runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertEquals(0, mManager.getPinnedShortcuts().size());
+ });
+
+ // Restore launcher 2 on user 0.
+ installPackage(USER_0, LAUNCHER_2);
+ runWithCaller(LAUNCHER_2, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+ "s2");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+ "s2", "s3");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* wasn't restored, so still empty */ );
+
+ assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+ });
+
+
+ // Restoration of launcher2 shouldn't affect other packages; so do the same checks and
+ // make sure they still have the same result.
+ installPackage(USER_0, CALLING_PACKAGE_1);
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllPinned(
+ mManager.getPinnedShortcuts()),
+ "s1", "s2");
+ });
+
+ installPackage(USER_0, LAUNCHER_1);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+ "s1");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+ "s1", "s2");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* wasn't restored, so still empty */ );
+
+ assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+ });
+
+ installPackage(USER_0, CALLING_PACKAGE_2);
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllPinned(
+ mManager.getPinnedShortcuts()),
+ "s1", "s2", "s3");
+ });
+ }
+
+ public void testBackupAndRestore_publisherLowerVersion() {
+ prepareForBackupTest();
+
+ // Note doing a backup & restore again here shouldn't affect the result.
+ backupAndRestore();
+
+ addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 0); // Lower version
+
+ checkBackupAndRestore_publisherNotRestored();
+ }
+
+ public void testBackupAndRestore_publisherWrongSignature() {
+ prepareForBackupTest();
+
+ // Note doing a backup & restore again here shouldn't affect the result.
+ backupAndRestore();
+
+ addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 10, "sigx"); // different signature
+
+ checkBackupAndRestore_publisherNotRestored();
+ }
+
+ public void testBackupAndRestore_publisherNoLongerBackupTarget() {
+ prepareForBackupTest();
+
+ // Note doing a backup & restore again here shouldn't affect the result.
+ backupAndRestore();
+
+ updatePackageInfo(CALLING_PACKAGE_1,
+ pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+ checkBackupAndRestore_publisherNotRestored();
+ }
+
+ private void checkBackupAndRestore_publisherNotRestored() {
+ installPackage(USER_0, CALLING_PACKAGE_1);
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertEquals(0, mManager.getPinnedShortcuts().size());
+ });
+
+ installPackage(USER_0, CALLING_PACKAGE_2);
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllPinned(
+ mManager.getPinnedShortcuts()),
+ "s1", "s2", "s3");
+ });
+
+ installPackage(USER_0, LAUNCHER_1);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+ "s1", "s2");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+ installPackage(USER_0, LAUNCHER_2);
+ runWithCaller(LAUNCHER_2, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+ "s2", "s3");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+
+ installPackage(USER_0, CALLING_PACKAGE_3);
+ runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertEquals(0, mManager.getPinnedShortcuts().size());
+ });
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+ "s1", "s2");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+ runWithCaller(LAUNCHER_2, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+ "s2", "s3");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+ }
+
+ public void testBackupAndRestore_launcherLowerVersion() {
+ prepareForBackupTest();
+
+ // Note doing a backup & restore again here shouldn't affect the result.
+ backupAndRestore();
+
+ addPackage(LAUNCHER_1, LAUNCHER_UID_1, 0); // Lower version
+
+ checkBackupAndRestore_launcherNotRestored();
+ }
+
+ public void testBackupAndRestore_launcherWrongSignature() {
+ prepareForBackupTest();
+
+ // Note doing a backup & restore again here shouldn't affect the result.
+ backupAndRestore();
+
+ addPackage(LAUNCHER_1, LAUNCHER_UID_1, 10, "sigx"); // different signature
+
+ checkBackupAndRestore_launcherNotRestored();
+ }
+
+ public void testBackupAndRestore_launcherNoLongerBackupTarget() {
+ prepareForBackupTest();
+
+ // Note doing a backup & restore again here shouldn't affect the result.
+ backupAndRestore();
+
+ updatePackageInfo(LAUNCHER_1,
+ pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+ checkBackupAndRestore_launcherNotRestored();
+ }
+
+ private void checkBackupAndRestore_launcherNotRestored() {
+ installPackage(USER_0, CALLING_PACKAGE_1);
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+
+ // s1 was pinned by launcher 1, which is not restored, yet, so we still see "s1" here.
+ assertShortcutIds(assertAllPinned(
+ mManager.getPinnedShortcuts()),
+ "s1", "s2");
+ });
+
+ installPackage(USER_0, CALLING_PACKAGE_2);
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllPinned(
+ mManager.getPinnedShortcuts()),
+ "s1", "s2", "s3");
+ });
+
+ // Now we try to restore launcher 1. Then we realize it's not restorable, so L1 has no pinned
+ // shortcuts.
+ installPackage(USER_0, LAUNCHER_1);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+
+ // Now CALLING_PACKAGE_1 realizes "s1" is no longer pinned.
+ assertShortcutIds(assertAllPinned(
+ mManager.getPinnedShortcuts()),
+ "s2");
+ });
+
+ installPackage(USER_0, LAUNCHER_2);
+ runWithCaller(LAUNCHER_2, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+ "s2");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+ "s2", "s3");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+
+ installPackage(USER_0, CALLING_PACKAGE_3);
+ runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertEquals(0, mManager.getPinnedShortcuts().size());
+ });
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+ runWithCaller(LAUNCHER_2, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+ "s2");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+ "s2", "s3");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+ }
+
+ public void testBackupAndRestore_launcherAndPackageNoLongerBackupTarget() {
+ prepareForBackupTest();
+
+ // Note doing a backup & restore again here shouldn't affect the result.
+ backupAndRestore();
+
+ updatePackageInfo(CALLING_PACKAGE_1,
+ pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+ updatePackageInfo(LAUNCHER_1,
+ pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+ checkBackupAndRestore_publisherAndLauncherNotRestored();
+ }
+
+ private void checkBackupAndRestore_publisherAndLauncherNotRestored() {
+ installPackage(USER_0, CALLING_PACKAGE_1);
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertEquals(0, mManager.getPinnedShortcuts().size());
+ });
+
+ installPackage(USER_0, CALLING_PACKAGE_2);
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllPinned(
+ mManager.getPinnedShortcuts()),
+ "s1", "s2", "s3");
+ });
+
+ installPackage(USER_0, LAUNCHER_1);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+ installPackage(USER_0, LAUNCHER_2);
+ runWithCaller(LAUNCHER_2, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+ "s2", "s3");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+
+ // Because launcher 1 wasn't restored, "s1" is no longer pinned.
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllPinned(
+ mManager.getPinnedShortcuts()),
+ "s2", "s3");
+ });
+
+ installPackage(USER_0, CALLING_PACKAGE_3);
+ runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertEquals(0, mManager.getPinnedShortcuts().size());
+ });
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+ runWithCaller(LAUNCHER_2, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+ "s2", "s3");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+ }
+
+ public void testSaveAndLoad_crossProfile() {
+ prepareCrossProfileDataSet();
+
+ dumpsysOnLogcat("Before save & load");
+
+ mService.saveDirtyInfo();
+ initService();
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+ "s1", "s2", "s3");
+ assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+ "s1", "s2", "s3", "s4");
+ });
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+ "s1", "s2", "s3");
+ assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+ "s1", "s2", "s3", "s4", "s5");
+ });
+ runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+ assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+ "s1", "s2", "s3");
+ assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+ "s1", "s2", "s3", "s4", "s5", "s6");
+ });
+ runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+ assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts())
+ /* empty */);
+ assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts())
+ /* empty */);
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+ assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+ "s1", "s2", "s3");
+ assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+ "s1", "s2", "s3", "s4", "s5", "s6");
+ });
+ runWithCaller(CALLING_PACKAGE_2, USER_P0, () -> {
+ assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts())
+ /* empty */);
+ assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts())
+ /* empty */);
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+ "x1", "x2", "x3");
+ assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+ "x4", "x5");
+ });
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
+ "s1");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
+ "s1", "s2");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
+ "s1", "s2", "s3");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
+ /* empty */);
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
+ "s1", "s4");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
+ /* empty */);
+ TestUtils.assertExpectException(
+ SecurityException.class, "", () -> {
+ mLauncherApps.getShortcuts(
+ buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10);
+ });
+ });
+ runWithCaller(LAUNCHER_2, USER_0, () -> {
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
+ "s2");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
+ "s2", "s3");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
+ "s2", "s3", "s4");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
+ /* empty */);
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
+ "s2", "s5");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
+ /* empty */);
+ });
+ runWithCaller(LAUNCHER_3, USER_0, () -> {
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
+ "s3");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
+ "s3", "s4");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
+ "s3", "s4", "s5");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
+ /* empty */);
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
+ "s3", "s6");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
+ /* empty */);
+ });
+ runWithCaller(LAUNCHER_4, USER_0, () -> {
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0)
+ /* empty */);
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0)
+ /* empty */);
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0)
+ /* empty */);
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
+ /* empty */);
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0)
+ /* empty */);
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
+ /* empty */);
+ });
+ runWithCaller(LAUNCHER_1, USER_P0, () -> {
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
+ "s3", "s4");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
+ "s3", "s4", "s5");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
+ "s3", "s4", "s5", "s6");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
+ "s1", "s4");
+ TestUtils.assertExpectException(
+ SecurityException.class, "unrelated profile", () -> {
+ mLauncherApps.getShortcuts(
+ buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10);
+ });
+ });
+ runWithCaller(LAUNCHER_1, USER_10, () -> {
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_10),
+ "x4", "x5");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_10)
+ /* empty */);
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_10)
+ /* empty */);
+ TestUtils.assertExpectException(
+ SecurityException.class, "unrelated profile", () -> {
+ mLauncherApps.getShortcuts(
+ buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0);
+ });
+ TestUtils.assertExpectException(
+ SecurityException.class, "unrelated profile", () -> {
+ mLauncherApps.getShortcuts(
+ buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_P0);
+ });
+ });
+ }
+
+ // ShortcutInfo tests
+
+ public void testShortcutInfoMissingMandatoryFields() {
+ TestUtils.assertExpectException(
+ IllegalArgumentException.class,
+ "ID must be provided",
+ () -> new ShortcutInfo.Builder(getTestContext()).build());
+ TestUtils.assertExpectException(
+ IllegalArgumentException.class,
+ "title must be provided",
+ () -> new ShortcutInfo.Builder(getTestContext()).setId("id").build()
+ .enforceMandatoryFields());
+ TestUtils.assertExpectException(
+ NullPointerException.class,
+ "Intent must be provided",
+ () -> new ShortcutInfo.Builder(getTestContext()).setId("id").setTitle("x").build()
+ .enforceMandatoryFields());
+ }
+
+ public void testShortcutInfoParcel() {
+ ShortcutInfo si = parceled(new ShortcutInfo.Builder(getTestContext())
+ .setId("id")
+ .setTitle("title")
+ .setIntent(makeIntent("action", ShortcutActivity.class))
+ .build());
+ assertEquals(getTestContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals("title", si.getTitle());
+ assertEquals("action", si.getIntent().getAction());
+
+ PersistableBundle pb = new PersistableBundle();
+ pb.putInt("k", 1);
+
+ si = new ShortcutInfo.Builder(getTestContext())
+ .setId("id")
+ .setActivityComponent(new ComponentName("a", "b"))
+ .setIcon(Icon.createWithContentUri("content://a.b.c/"))
+ .setTitle("title")
+ .setText("text")
+ .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+ .setWeight(123)
+ .setExtras(pb)
+ .build();
+ si.addFlags(ShortcutInfo.FLAG_PINNED);
+ si.setBitmapPath("abc");
+ si.setIconResourceId(456);
+
+ si = parceled(si);
+
+ assertEquals(getTestContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
+ assertEquals("content://a.b.c/", si.getIcon().getUriString());
+ assertEquals("title", si.getTitle());
+ assertEquals("text", si.getText());
+ assertEquals("action", si.getIntent().getAction());
+ assertEquals("val", si.getIntent().getStringExtra("key"));
+ assertEquals(123, si.getWeight());
+ assertEquals(1, si.getExtras().getInt("k"));
+
+ assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+ assertEquals("abc", si.getBitmapPath());
+ assertEquals(456, si.getIconResourceId());
+ }
+
+ public void testShortcutInfoClone() {
+ PersistableBundle pb = new PersistableBundle();
+ pb.putInt("k", 1);
+ ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext())
+ .setId("id")
+ .setActivityComponent(new ComponentName("a", "b"))
+ .setIcon(Icon.createWithContentUri("content://a.b.c/"))
+ .setTitle("title")
+ .setText("text")
+ .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+ .setWeight(123)
+ .setExtras(pb)
+ .build();
+ sorig.addFlags(ShortcutInfo.FLAG_PINNED);
+ sorig.setBitmapPath("abc");
+ sorig.setIconResourceId(456);
+
+ ShortcutInfo si = sorig.clone(/* clone flags*/ 0);
+
+ assertEquals(getTestContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
+ assertEquals("content://a.b.c/", si.getIcon().getUriString());
+ assertEquals("title", si.getTitle());
+ assertEquals("text", si.getText());
+ assertEquals("action", si.getIntent().getAction());
+ assertEquals("val", si.getIntent().getStringExtra("key"));
+ assertEquals(123, si.getWeight());
+ assertEquals(1, si.getExtras().getInt("k"));
+
+ assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+ assertEquals("abc", si.getBitmapPath());
+ assertEquals(456, si.getIconResourceId());
+
+ si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
+
+ assertEquals(getTestContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
+ assertEquals(null, si.getIcon());
+ assertEquals("title", si.getTitle());
+ assertEquals("text", si.getText());
+ assertEquals("action", si.getIntent().getAction());
+ assertEquals("val", si.getIntent().getStringExtra("key"));
+ assertEquals(123, si.getWeight());
+ assertEquals(1, si.getExtras().getInt("k"));
+
+ assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+ assertEquals(null, si.getBitmapPath());
+ assertEquals(0, si.getIconResourceId());
+
+ si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
+
+ assertEquals(getTestContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
+ assertEquals(null, si.getIcon());
+ assertEquals("title", si.getTitle());
+ assertEquals("text", si.getText());
+ assertEquals(null, si.getIntent());
+ assertEquals(123, si.getWeight());
+ assertEquals(1, si.getExtras().getInt("k"));
+
+ assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+ assertEquals(null, si.getBitmapPath());
+ assertEquals(0, si.getIconResourceId());
+
+ si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
+
+ assertEquals(getTestContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals(null, si.getActivityComponent());
+ assertEquals(null, si.getIcon());
+ assertEquals(null, si.getTitle());
+ assertEquals(null, si.getText());
+ assertEquals(null, si.getIntent());
+ assertEquals(0, si.getWeight());
+ assertEquals(null, si.getExtras());
+
+ assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY, si.getFlags());
+ assertEquals(null, si.getBitmapPath());
+ assertEquals(0, si.getIconResourceId());
+ }
+
+ public void testShortcutInfoCopyNonNullFieldsFrom() throws InterruptedException {
+ PersistableBundle pb = new PersistableBundle();
+ pb.putInt("k", 1);
+ ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext())
+ .setId("id")
+ .setActivityComponent(new ComponentName("a", "b"))
+ .setIcon(Icon.createWithContentUri("content://a.b.c/"))
+ .setTitle("title")
+ .setText("text")
+ .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+ .setWeight(123)
+ .setExtras(pb)
+ .build();
+ sorig.addFlags(ShortcutInfo.FLAG_PINNED);
+ sorig.setBitmapPath("abc");
+ sorig.setIconResourceId(456);
+
+ ShortcutInfo si;
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+ .setActivityComponent(new ComponentName("x", "y")).build());
+ assertEquals(new ComponentName("x", "y"), si.getActivityComponent());
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+ .setIcon(Icon.createWithContentUri("content://x.y.z/")).build());
+ assertEquals("content://x.y.z/", si.getIcon().getUriString());
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+ .setTitle("xyz").build());
+ assertEquals("xyz", si.getTitle());
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+ .setText("xxx").build());
+ assertEquals("xxx", si.getText());
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+ .setIntent(makeIntent("action2", ShortcutActivity.class)).build());
+ assertEquals("action2", si.getIntent().getAction());
+ assertEquals(null, si.getIntent().getStringExtra("key"));
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+ .setIntent(makeIntent("action3", ShortcutActivity.class, "key", "x")).build());
+ assertEquals("action3", si.getIntent().getAction());
+ assertEquals("x", si.getIntent().getStringExtra("key"));
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+ .setWeight(999).build());
+ assertEquals(999, si.getWeight());
+
+
+ PersistableBundle pb2 = new PersistableBundle();
+ pb2.putInt("x", 99);
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+ .setExtras(pb2).build());
+ assertEquals(99, si.getExtras().getInt("x"));
+
+ final long timestamp = si.getLastChangedTimestamp();
+ Thread.sleep(2);
+
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+ .setTitle("xyz").build());
+
+ assertTrue(si.getLastChangedTimestamp() > timestamp);
+ }
+
+ public void testShortcutInfoSaveAndLoad() throws InterruptedException {
+ setCaller(CALLING_PACKAGE_1, USER_0);
+
+ final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+ getTestContext().getResources(), R.drawable.black_32x32));
+
+ PersistableBundle pb = new PersistableBundle();
+ pb.putInt("k", 1);
+ ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
+ .setId("id")
+ .setActivityComponent(new ComponentName(mClientContext, ShortcutActivity2.class))
+ .setIcon(bmp32x32)
+ .setTitle("title")
+ .setText("text")
+ .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+ .setWeight(123)
+ .setExtras(pb)
+ .build();
+
+ mManager.addDynamicShortcut(sorig);
+
+ Thread.sleep(2);
+ final long now = System.currentTimeMillis();
+
+ // Save and load.
+ mService.saveDirtyInfo();
+ initService();
+ mService.handleUnlockUser(USER_0);
+
+ ShortcutInfo si;
+ si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0);
+
+ assertEquals(CALLING_PACKAGE_1, si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals(ShortcutActivity2.class.getName(), si.getActivityComponent().getClassName());
+ assertEquals(null, si.getIcon());
+ assertEquals("title", si.getTitle());
+ assertEquals("text", si.getText());
+ assertEquals("action", si.getIntent().getAction());
+ assertEquals("val", si.getIntent().getStringExtra("key"));
+ assertEquals(123, si.getWeight());
+ assertEquals(1, si.getExtras().getInt("k"));
+
+ assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_FILE, si.getFlags());
+ assertNotNull(si.getBitmapPath()); // Something should be set.
+ assertEquals(0, si.getIconResourceId());
+ assertTrue(si.getLastChangedTimestamp() < now);
+ }
+
+ public void testShortcutInfoSaveAndLoad_forBackup() {
+ setCaller(CALLING_PACKAGE_1, USER_0);
+
+ final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+ getTestContext().getResources(), R.drawable.black_32x32));
+
+ PersistableBundle pb = new PersistableBundle();
+ pb.putInt("k", 1);
+ ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
+ .setId("id")
+ .setActivityComponent(new ComponentName(mClientContext, ShortcutActivity2.class))
+ .setIcon(bmp32x32)
+ .setTitle("title")
+ .setText("text")
+ .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+ .setWeight(123)
+ .setExtras(pb)
+ .build();
+
+ mManager.addDynamicShortcut(sorig);
+
+ // Dynamic shortcuts won't be backed up, so we need to pin it.
+ setCaller(LAUNCHER_1, USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id"), HANDLE_USER_0);
+
+ // Do backup & restore.
+ backupAndRestore();
+
+ ShortcutInfo si;
+ si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0);
+
+ assertEquals(CALLING_PACKAGE_1, si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals(ShortcutActivity2.class.getName(), si.getActivityComponent().getClassName());
+ assertEquals(null, si.getIcon());
+ assertEquals("title", si.getTitle());
+ assertEquals("text", si.getText());
+ assertEquals("action", si.getIntent().getAction());
+ assertEquals("val", si.getIntent().getStringExtra("key"));
+ assertEquals(123, si.getWeight());
+ assertEquals(1, si.getExtras().getInt("k"));
+
+ assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+ assertNull(si.getBitmapPath()); // No icon.
+ assertEquals(0, si.getIconResourceId());
+ }
+
+ public void testDumpsys_crossProfile() {
+ prepareCrossProfileDataSet();
+ dumpsysOnLogcat("test1", /* force= */ true);
+ }
+
+ public void testDumpsys_withIcons() {
+ testIcons();
+ // Dump after having some icons.
+ dumpsysOnLogcat("test1", /* force= */ true);
}
}
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index b56ce73..dbc2b0c 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -170,6 +170,15 @@
public static final int CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE = 0x100;
/**
+ * Flag indicating that for this {@link PhoneAccount}, emergency video calling is allowed.
+ * <p>
+ * When set, Telecom will allow emergency video calls to be placed. When not set, Telecom will
+ * convert all outgoing video calls to emergency numbers to audio-only.
+ * @hide
+ */
+ public static final int CAPABILITY_EMERGENCY_VIDEO_CALLING = 0x200;
+
+ /**
* URI scheme for telephone number URIs.
*/
public static final String SCHEME_TEL = "tel";
@@ -731,6 +740,9 @@
if (hasCapabilities(CAPABILITY_PLACE_EMERGENCY_CALLS)) {
sb.append("PlaceEmerg ");
}
+ if (hasCapabilities(CAPABILITY_EMERGENCY_VIDEO_CALLING)) {
+ sb.append("EmergVideo ");
+ }
if (hasCapabilities(CAPABILITY_SIM_SUBSCRIPTION)) {
sb.append("SimSub ");
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index c69a360..461611d 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -252,6 +252,16 @@
public static final String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
/**
+ * Flag specifying whether WFC over IMS supports the "wifi only" option. If false, the wifi
+ * calling settings will not include an option for "wifi only". If true, the wifi calling
+ * settings will include an option for "wifi only"
+ * <p>
+ * By default, it is assumed that WFC supports "wifi only".
+ */
+ public static final String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL =
+ "carrier_wfc_supports_wifi_only_bool";
+
+ /**
* Default WFC_IMS_mode 0: WIFI_ONLY
* 1: CELLULAR_PREFERRED
* 2: WIFI_PREFERRED
@@ -628,6 +638,7 @@
sDefaults.putBoolean(KEY_CARRIER_VOLTE_AVAILABLE_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_VT_AVAILABLE_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL, false);
+ sDefaults.putBoolean(KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, true);
sDefaults.putBoolean(KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL, false);
sDefaults.putInt(KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT, 2);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index b482811..865af78 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3550,7 +3550,7 @@
* @return the response of ISIM Authetification, or null if not available
* @hide
* @deprecated
- * @see getIccSimChallengeResponse with appType=PhoneConstants.APPTYPE_ISIM
+ * @see getIccAuthentication with appType=PhoneConstants.APPTYPE_ISIM
*/
public String getIsimChallengeResponse(String nonce){
try {
@@ -3566,21 +3566,60 @@
}
}
+ // ICC SIM Application Types
+ public static final int APPTYPE_SIM = PhoneConstants.APPTYPE_SIM;
+ public static final int APPTYPE_USIM = PhoneConstants.APPTYPE_USIM;
+ public static final int APPTYPE_RUIM = PhoneConstants.APPTYPE_RUIM;
+ public static final int APPTYPE_CSIM = PhoneConstants.APPTYPE_CSIM;
+ public static final int APPTYPE_ISIM = PhoneConstants.APPTYPE_ISIM;
+ // authContext (parameter P2) when doing SIM challenge,
+ // per 3GPP TS 31.102 (Section 7.1.2)
+ public static final int AUTHTYPE_EAP_SIM = PhoneConstants.AUTH_CONTEXT_EAP_SIM;
+ public static final int AUTHTYPE_EAP_AKA = PhoneConstants.AUTH_CONTEXT_EAP_AKA;
+
/**
- * Returns the response of SIM Authentication through RIL.
- * Returns null if the Authentication hasn't been successful
- * @param subId subscription ID to be queried
- * @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
- * @param data authentication challenge data
- * @return the response of SIM Authentication, or null if not available
- * @hide
+ * Returns the response of authentication for the default subscription.
+ * Returns null if the authentication hasn't been successful
+ *
+ * <p>Requires that the calling app has carrier privileges or READ_PRIVILEGED_PHONE_STATE
+ * permission.
+ *
+ * @param appType the icc application type, like {@link #APPTYPE_USIM}
+ * @param authType the authentication type, {@link #AUTHTYPE_EAP_AKA} or
+ * {@link #AUTHTYPE_EAP_SIM}
+ * @param data authentication challenge data, base64 encoded.
+ * See 3GPP TS 31.102 7.1.2 for more details.
+ * @return the response of authentication, or null if not available
+ *
+ * @see #hasCarrierPrivileges
*/
- public String getIccSimChallengeResponse(int subId, int appType, String data) {
+ public String getIccAuthentication(int appType, int authType, String data) {
+ return getIccAuthentication(getDefaultSubscription(), appType, authType, data);
+ }
+
+ /**
+ * Returns the response of USIM Authentication for specified subId.
+ * Returns null if the authentication hasn't been successful
+ *
+ * <p>Requires that the calling app has carrier privileges.
+ *
+ * @param subId subscription ID used for authentication
+ * @param appType the icc application type, like {@link #APPTYPE_USIM}
+ * @param authType the authentication type, {@link #AUTHTYPE_EAP_AKA} or
+ * {@link #AUTHTYPE_EAP_SIM}
+ * @param data authentication challenge data, base64 encoded.
+ * See 3GPP TS 31.102 7.1.2 for more details.
+ * @return the response of authentication, or null if not available
+ *
+ * @see #hasCarrierPrivileges
+ */
+
+ public String getIccAuthentication(int subId, int appType, int authType, String data) {
try {
IPhoneSubInfo info = getSubscriberInfo();
if (info == null)
return null;
- return info.getIccSimChallengeResponse(subId, appType, data);
+ return info.getIccSimChallengeResponse(subId, appType, authType, data);
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -3599,9 +3638,10 @@
* @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
* @param data authentication challenge data
* @return the response of SIM Authentication, or null if not available
+ * @hide
*/
public String getIccSimChallengeResponse(int appType, String data) {
- return getIccSimChallengeResponse(getDefaultSubscription(), appType, data);
+ return getIccAuthentication(getDefaultSubscription(), appType, AUTHTYPE_EAP_SIM, data);
}
/**
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index dc2b297..02baa34 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -196,8 +196,9 @@
*
* @param subId subscription ID to be queried
* @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
+ * @param authType Authentication type, see PhoneConstants#AUTHTYPE_xxx
* @param data authentication challenge data
* @return challenge response
*/
- String getIccSimChallengeResponse(int subId, int appType, String data);
+ String getIccSimChallengeResponse(int subId, int appType, int authType, String data);
}
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index ecd89ed..1680fe3 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -202,4 +202,10 @@
public static final int AUDIO_OUTPUT_ENABLE_SPEAKER = 0;
public static final int AUDIO_OUTPUT_DISABLE_SPEAKER = 1;
public static final int AUDIO_OUTPUT_DEFAULT = AUDIO_OUTPUT_ENABLE_SPEAKER;
+
+ // authContext (parameter P2) when doing SIM challenge,
+ // per 3GPP TS 31.102 (Section 7.1.2)
+ public static final int AUTH_CONTEXT_EAP_SIM = 128;
+ public static final int AUTH_CONTEXT_EAP_AKA = 129;
+ public static final int AUTH_CONTEXT_UNDEFINED = -1;
}
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index ed7351f8..033312b 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -62,7 +62,7 @@
private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts";
private static final String WEARABLE_ACTION_GOOGLE =
"com.google.android.wearable.action.GOOGLE";
- private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 7500; //7.5s to allow app to idle
+ private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 60000; //60s to allow app to idle
private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; //750ms idle for non initial launches
private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 2000; //2s between launching apps
diff --git a/tests/SoundTriggerTests/src/android/hardware/soundtrigger/stubhal/GenericSoundModelTest.java b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/stubhal/GenericSoundModelTest.java
index ad02d2b..c0583ce 100644
--- a/tests/SoundTriggerTests/src/android/hardware/soundtrigger/stubhal/GenericSoundModelTest.java
+++ b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/stubhal/GenericSoundModelTest.java
@@ -18,6 +18,7 @@
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
@@ -40,6 +41,7 @@
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.Random;
import java.util.UUID;
@@ -53,7 +55,7 @@
static final int MSG_GENERIC_TRIGGER = 4;
private Random random = new Random();
- private ArrayList<UUID> loadedModelUuids;
+ private HashSet<UUID> loadedModelUuids;
private ISoundTriggerService soundTriggerService;
private SoundTriggerManager soundTriggerManager;
@@ -68,7 +70,7 @@
soundTriggerManager = (SoundTriggerManager) context.getSystemService(
Context.SOUND_TRIGGER_SERVICE);
- loadedModelUuids = new ArrayList<UUID>();
+ loadedModelUuids = new HashSet<UUID>();
}
@Override
@@ -170,6 +172,101 @@
verify(spyCallback, timeout(100)).onGenericSoundTriggerDetected(any());
}
+ /**
+ * Tests a more complicated pattern of loading, unloading, triggering, starting and stopping
+ * recognition. Intended to find unexpected errors that occur in unexpected states.
+ */
+ @LargeTest
+ public void testFuzzGenericSoundModel() throws Exception {
+ int numModels = 2;
+
+ final int STATUS_UNLOADED = 0;
+ final int STATUS_LOADED = 1;
+ final int STATUS_STARTED = 2;
+
+ class ModelInfo {
+ int status;
+ GenericSoundModel model;
+
+ public ModelInfo(GenericSoundModel model, int status) {
+ this.status = status;
+ this.model = model;
+ }
+ }
+
+ Random predictableRandom = new Random(100);
+
+ ArrayList modelInfos = new ArrayList<ModelInfo>();
+ for(int i=0; i<numModels; i++) {
+ // Create sound model
+ byte[] data = new byte[1024];
+ predictableRandom.nextBytes(data);
+ UUID modelUuid = UUID.randomUUID();
+ UUID mVendorUuid = UUID.randomUUID();
+ GenericSoundModel model = new GenericSoundModel(modelUuid, mVendorUuid, data);
+ ModelInfo modelInfo = new ModelInfo(model, STATUS_UNLOADED);
+ modelInfos.add(modelInfo);
+ }
+
+ boolean captureTriggerAudio = true;
+ boolean allowMultipleTriggers = true;
+ RecognitionConfig config = new RecognitionConfig(captureTriggerAudio, allowMultipleTriggers,
+ null, null);
+ TestRecognitionStatusCallback spyCallback = spy(new TestRecognitionStatusCallback());
+
+
+ int numOperationsToRun = 100;
+ for(int i=0; i<numOperationsToRun; i++) {
+ // Select a random model
+ int modelInfoIndex = predictableRandom.nextInt(modelInfos.size());
+ ModelInfo modelInfo = (ModelInfo) modelInfos.get(modelInfoIndex);
+
+ // Perform a random operation
+ int operation = predictableRandom.nextInt(5);
+
+ if (operation == 0 && modelInfo.status == STATUS_UNLOADED) {
+ // Update and start sound model
+ soundTriggerService.updateSoundModel(modelInfo.model);
+ loadedModelUuids.add(modelInfo.model.uuid);
+ modelInfo.status = STATUS_LOADED;
+ } else if (operation == 1 && modelInfo.status == STATUS_LOADED) {
+ // Start the sound model
+ int r = soundTriggerService.startRecognition(new ParcelUuid(modelInfo.model.uuid),
+ spyCallback, config);
+ assertEquals("Could Not Start Recognition with code: " + r,
+ android.hardware.soundtrigger.SoundTrigger.STATUS_OK, r);
+ modelInfo.status = STATUS_STARTED;
+ } else if (operation == 2 && modelInfo.status == STATUS_STARTED) {
+ // Send trigger to stub HAL
+ Socket socket = new Socket(InetAddress.getLocalHost(), 14035);
+ DataOutputStream out = new DataOutputStream(socket.getOutputStream());
+ out.writeBytes("trig " + modelInfo.model.uuid + "\r\n");
+ out.flush();
+ socket.close();
+
+ // Verify trigger was received
+ verify(spyCallback, timeout(100)).onGenericSoundTriggerDetected(any());
+ reset(spyCallback);
+ } else if (operation == 3 && modelInfo.status == STATUS_STARTED) {
+ // Stop recognition
+ int r = soundTriggerService.stopRecognition(new ParcelUuid(modelInfo.model.uuid),
+ spyCallback);
+ assertEquals("Could Not Stop Recognition with code: " + r,
+ android.hardware.soundtrigger.SoundTrigger.STATUS_OK, r);
+ modelInfo.status = STATUS_LOADED;
+ } else if (operation == 4 && modelInfo.status != STATUS_UNLOADED) {
+ // Delete sound model
+ soundTriggerService.deleteSoundModel(new ParcelUuid(modelInfo.model.uuid));
+ loadedModelUuids.remove(modelInfo.model.uuid);
+
+ // Confirm it was deleted
+ GenericSoundModel returnedModel =
+ soundTriggerService.getSoundModel(new ParcelUuid(modelInfo.model.uuid));
+ assertEquals(null, returnedModel);
+ modelInfo.status = STATUS_UNLOADED;
+ }
+ }
+ }
public class TestRecognitionStatusCallback extends IRecognitionStatusCallback.Stub {
@Override
diff --git a/tests/VectorDrawableTest/Android.mk b/tests/VectorDrawableTest/Android.mk
index 3d44e33..dd8a4d4 100644
--- a/tests/VectorDrawableTest/Android.mk
+++ b/tests/VectorDrawableTest/Android.mk
@@ -23,6 +23,4 @@
LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
-
include $(BUILD_PACKAGE)
diff --git a/tests/VectorDrawableTest/AndroidManifest.xml b/tests/VectorDrawableTest/AndroidManifest.xml
index e648897..7b3beb2 100644
--- a/tests/VectorDrawableTest/AndroidManifest.xml
+++ b/tests/VectorDrawableTest/AndroidManifest.xml
@@ -18,8 +18,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.test.dynamic" >
- <uses-sdk android:minSdkVersion="21" />
-
<application
android:hardwareAccelerated="true"
android:label="vector"
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
index 4026e5e..8f538ae 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
@@ -24,6 +24,7 @@
import android.widget.Button;
import android.widget.GridLayout;
import android.widget.ScrollView;
+import android.widget.TextView;
public class AnimatedVectorDrawableTest extends Activity implements View.OnClickListener {
private static final String LOGCAT = "AnimatedVectorDrawableTest";
@@ -45,35 +46,51 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
final int[] layerTypes = {View.LAYER_TYPE_SOFTWARE, View.LAYER_TYPE_HARDWARE};
+ final boolean[] forceOnUi = {false, true};
super.onCreate(savedInstanceState);
ScrollView scrollView = new ScrollView(this);
GridLayout container = new GridLayout(this);
scrollView.addView(container);
- container.setColumnCount(2);
+ container.setColumnCount(layerTypes.length * forceOnUi.length);
+ for (int j = 0; j < layerTypes.length; j++) {
+ for (int k = 0; k < forceOnUi.length; k++) {
+ TextView textView = new TextView(this);
+ String category = "Layer:"
+ + (layerTypes[j] == View.LAYER_TYPE_SOFTWARE ? "SW" : "HW")
+ + (forceOnUi[k] == true ? ",forceUI" : "");
+ textView.setText(category);
+ container.addView(textView);
+ }
+ }
for (int i = 0; i < icon.length; i++) {
for (int j = 0; j < layerTypes.length; j++) {
- Button button = new Button(this);
- button.setWidth(400);
- button.setHeight(400);
- button.setLayerType(layerTypes[j], null);
- button.setBackgroundResource(icon[i]);
- AnimatedVectorDrawable d = (AnimatedVectorDrawable) button.getBackground();
- d.registerAnimationCallback(new Animatable2.AnimationCallback() {
- @Override
- public void onAnimationStart(Drawable drawable) {
- Log.v(LOGCAT, "Animator start");
+ for (int k = 0; k < forceOnUi.length; k++) {
+ Button button = new Button(this);
+ button.setWidth(300);
+ button.setHeight(300);
+ button.setLayerType(layerTypes[j], null);
+ button.setBackgroundResource(icon[i]);
+ AnimatedVectorDrawable d = (AnimatedVectorDrawable) button.getBackground();
+ if (forceOnUi[k] == true) {
+ d.forceAnimationOnUI();
}
+ d.registerAnimationCallback(new Animatable2.AnimationCallback() {
+ @Override
+ public void onAnimationStart(Drawable drawable) {
+ Log.v(LOGCAT, "Animator start");
+ }
- @Override
- public void onAnimationEnd(Drawable drawable) {
- Log.v(LOGCAT, "Animator end");
- }
- });
+ @Override
+ public void onAnimationEnd(Drawable drawable) {
+ Log.v(LOGCAT, "Animator end");
+ }
+ });
- container.addView(button);
- button.setOnClickListener(this);
+ container.addView(button);
+ button.setOnClickListener(this);
+ }
}
}
diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp
index 641c34b..d631f35 100644
--- a/tools/aapt/Package.cpp
+++ b/tools/aapt/Package.cpp
@@ -33,7 +33,7 @@
".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet",
".rtttl", ".imy", ".xmf", ".mp4", ".m4a",
".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2",
- ".amr", ".awb", ".wma", ".wmv", ".webm"
+ ".amr", ".awb", ".wma", ".wmv", ".webm", ".mkv"
};
/* fwd decls, so I can write this downward */
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
index 85d22ff..876a422 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -54,6 +54,7 @@
Debug.cpp \
Flags.cpp \
java/AnnotationProcessor.cpp \
+ java/ClassDefinition.cpp \
java/JavaClassGenerator.cpp \
java/ManifestClassGenerator.cpp \
java/ProguardRules.cpp \
diff --git a/tools/aapt2/java/AnnotationProcessor.cpp b/tools/aapt2/java/AnnotationProcessor.cpp
index 496e92e..ba74439 100644
--- a/tools/aapt2/java/AnnotationProcessor.cpp
+++ b/tools/aapt2/java/AnnotationProcessor.cpp
@@ -64,7 +64,7 @@
mComment << "\n *";
}
-void AnnotationProcessor::writeToStream(std::ostream* out, const StringPiece& prefix) {
+void AnnotationProcessor::writeToStream(std::ostream* out, const StringPiece& prefix) const {
if (mHasComments) {
std::string result = mComment.str();
for (StringPiece line : util::tokenize<char>(result, '\n')) {
diff --git a/tools/aapt2/java/AnnotationProcessor.h b/tools/aapt2/java/AnnotationProcessor.h
index fadf584..0fc5b08 100644
--- a/tools/aapt2/java/AnnotationProcessor.h
+++ b/tools/aapt2/java/AnnotationProcessor.h
@@ -66,7 +66,7 @@
/**
* Writes the comments and annotations to the stream, with the given prefix before each line.
*/
- void writeToStream(std::ostream* out, const StringPiece& prefix);
+ void writeToStream(std::ostream* out, const StringPiece& prefix) const;
private:
enum : uint32_t {
diff --git a/tools/aapt2/java/ClassDefinition.cpp b/tools/aapt2/java/ClassDefinition.cpp
new file mode 100644
index 0000000..08f2c8b
--- /dev/null
+++ b/tools/aapt2/java/ClassDefinition.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "java/ClassDefinition.h"
+#include "util/StringPiece.h"
+
+#include <ostream>
+
+namespace aapt {
+
+bool ClassDefinition::empty() const {
+ for (const std::unique_ptr<ClassMember>& member : mMembers) {
+ if (!member->empty()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void ClassDefinition::writeToStream(const StringPiece& prefix, bool final,
+ std::ostream* out) const {
+ if (mMembers.empty() && !mCreateIfEmpty) {
+ return;
+ }
+
+ ClassMember::writeToStream(prefix, final, out);
+
+ *out << prefix << "public ";
+ if (mQualifier == ClassQualifier::Static) {
+ *out << "static ";
+ }
+ *out << "final class " << mName << " {\n";
+
+ std::string newPrefix = prefix.toString();
+ newPrefix.append(kIndent);
+
+ for (const std::unique_ptr<ClassMember>& member : mMembers) {
+ member->writeToStream(newPrefix, final, out);
+ *out << "\n";
+ }
+
+ *out << prefix << "}";
+}
+
+constexpr static const char* sWarningHeader =
+ "/* AUTO-GENERATED FILE. DO NOT MODIFY.\n"
+ " *\n"
+ " * This class was automatically generated by the\n"
+ " * aapt tool from the resource data it found. It\n"
+ " * should not be modified by hand.\n"
+ " */\n\n";
+
+bool ClassDefinition::writeJavaFile(const ClassDefinition* def,
+ const StringPiece& package,
+ bool final,
+ std::ostream* out) {
+ *out << sWarningHeader << "package " << package << ";\n\n";
+ def->writeToStream("", final, out);
+ return bool(*out);
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/java/ClassDefinition.h b/tools/aapt2/java/ClassDefinition.h
new file mode 100644
index 0000000..53e0f6f
--- /dev/null
+++ b/tools/aapt2/java/ClassDefinition.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef AAPT_JAVA_CLASSDEFINITION_H
+#define AAPT_JAVA_CLASSDEFINITION_H
+
+#include "Resource.h"
+#include "java/AnnotationProcessor.h"
+#include "util/StringPiece.h"
+#include "util/Util.h"
+
+#include <android-base/macros.h>
+#include <sstream>
+#include <string>
+
+namespace aapt {
+
+// The number of attributes to emit per line in a Styleable array.
+constexpr static size_t kAttribsPerLine = 4;
+constexpr static const char* kIndent = " ";
+
+class ClassMember {
+public:
+ virtual ~ClassMember() = default;
+
+ AnnotationProcessor* getCommentBuilder() {
+ return &mProcessor;
+ }
+
+ virtual bool empty() const = 0;
+
+ virtual void writeToStream(const StringPiece& prefix, bool final, std::ostream* out) const {
+ mProcessor.writeToStream(out, prefix);
+ }
+
+private:
+ AnnotationProcessor mProcessor;
+};
+
+template <typename T>
+class PrimitiveMember : public ClassMember {
+public:
+ PrimitiveMember(const StringPiece& name, const T& val) :
+ mName(name.toString()), mVal(val) {
+ }
+
+ bool empty() const override {
+ return false;
+ }
+
+ void writeToStream(const StringPiece& prefix, bool final, std::ostream* out) const override {
+ ClassMember::writeToStream(prefix, final, out);
+
+ *out << prefix << "public static " << (final ? "final " : "")
+ << "int " << mName << "=" << mVal << ";";
+ }
+
+private:
+ std::string mName;
+ T mVal;
+
+ DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
+};
+
+/**
+ * Specialization for strings so they get the right type and are quoted with "".
+ */
+template <>
+class PrimitiveMember<std::string> : public ClassMember {
+public:
+ PrimitiveMember(const StringPiece& name, const std::string& val) :
+ mName(name.toString()), mVal(val) {
+ }
+
+ bool empty() const override {
+ return false;
+ }
+
+ void writeToStream(const StringPiece& prefix, bool final, std::ostream* out) const override {
+ ClassMember::writeToStream(prefix, final, out);
+
+ *out << prefix << "public static " << (final ? "final " : "")
+ << "String " << mName << "=\"" << mVal << "\";";
+ }
+
+private:
+ std::string mName;
+ std::string mVal;
+
+ DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
+};
+
+using IntMember = PrimitiveMember<uint32_t>;
+using ResourceMember = PrimitiveMember<ResourceId>;
+using StringMember = PrimitiveMember<std::string>;
+
+template <typename T>
+class PrimitiveArrayMember : public ClassMember {
+public:
+ PrimitiveArrayMember(const StringPiece& name) :
+ mName(name.toString()) {
+ }
+
+ void addElement(const T& val) {
+ mElements.push_back(val);
+ }
+
+ bool empty() const override {
+ return false;
+ }
+
+ void writeToStream(const StringPiece& prefix, bool final, std::ostream* out) const override {
+ ClassMember::writeToStream(prefix, final, out);
+
+ *out << "public static final int[] " << mName << "={";
+
+ const auto begin = mElements.begin();
+ const auto end = mElements.end();
+ for (auto current = begin; current != end; ++current) {
+ if (std::distance(begin, current) % kAttribsPerLine == 0) {
+ *out << "\n" << prefix << kIndent << kIndent;
+ }
+
+ *out << *current;
+ if (std::distance(current, end) > 1) {
+ *out << ", ";
+ }
+ }
+ *out << "\n" << prefix << kIndent <<"};";
+ }
+
+private:
+ std::string mName;
+ std::vector<T> mElements;
+
+ DISALLOW_COPY_AND_ASSIGN(PrimitiveArrayMember);
+};
+
+using ResourceArrayMember = PrimitiveArrayMember<ResourceId>;
+
+enum class ClassQualifier {
+ None,
+ Static
+};
+
+class ClassDefinition : public ClassMember {
+public:
+ static bool writeJavaFile(const ClassDefinition* def,
+ const StringPiece& package,
+ bool final,
+ std::ostream* out);
+
+ ClassDefinition(const StringPiece& name, ClassQualifier qualifier, bool createIfEmpty) :
+ mName(name.toString()), mQualifier(qualifier), mCreateIfEmpty(createIfEmpty) {
+ }
+
+ void addMember(std::unique_ptr<ClassMember> member) {
+ mMembers.push_back(std::move(member));
+ }
+
+ bool empty() const override;
+ void writeToStream(const StringPiece& prefix, bool final, std::ostream* out) const override;
+
+private:
+ std::string mName;
+ ClassQualifier mQualifier;
+ bool mCreateIfEmpty;
+ std::vector<std::unique_ptr<ClassMember>> mMembers;
+
+ DISALLOW_COPY_AND_ASSIGN(ClassDefinition);
+};
+
+} // namespace aapt
+
+#endif /* AAPT_JAVA_CLASSDEFINITION_H */
diff --git a/tools/aapt2/java/ClassDefinitionWriter.h b/tools/aapt2/java/ClassDefinitionWriter.h
deleted file mode 100644
index cf92c9a..0000000
--- a/tools/aapt2/java/ClassDefinitionWriter.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#ifndef AAPT_JAVA_CLASSDEFINITION_H
-#define AAPT_JAVA_CLASSDEFINITION_H
-
-#include "Resource.h"
-#include "java/AnnotationProcessor.h"
-#include "util/StringPiece.h"
-#include "util/Util.h"
-
-#include <sstream>
-#include <string>
-
-namespace aapt {
-
-struct ClassDefinitionWriterOptions {
- bool useFinalQualifier = false;
- bool forceCreationIfEmpty = false;
-};
-
-/**
- * Writes a class for use in R.java or Manifest.java.
- */
-class ClassDefinitionWriter {
-public:
- ClassDefinitionWriter(const StringPiece& name, const ClassDefinitionWriterOptions& options) :
- mName(name.toString()), mOptions(options), mStarted(false) {
- }
-
- ClassDefinitionWriter(const StringPiece16& name, const ClassDefinitionWriterOptions& options) :
- mName(util::utf16ToUtf8(name)), mOptions(options), mStarted(false) {
- }
-
- void addIntMember(const StringPiece& name, AnnotationProcessor* processor,
- const uint32_t val) {
- ensureClassDeclaration();
- if (processor) {
- processor->writeToStream(&mOut, kIndent);
- }
- mOut << kIndent << "public static " << (mOptions.useFinalQualifier ? "final " : "")
- << "int " << name << "=" << val << ";\n";
- }
-
- void addStringMember(const StringPiece16& name, AnnotationProcessor* processor,
- const StringPiece16& val) {
- ensureClassDeclaration();
- if (processor) {
- processor->writeToStream(&mOut, kIndent);
- }
- mOut << kIndent << "public static " << (mOptions.useFinalQualifier ? "final " : "")
- << "String " << name << "=\"" << val << "\";\n";
- }
-
- void addResourceMember(const StringPiece& name, AnnotationProcessor* processor,
- const ResourceId id) {
- ensureClassDeclaration();
- if (processor) {
- processor->writeToStream(&mOut, kIndent);
- }
- mOut << kIndent << "public static " << (mOptions.useFinalQualifier ? "final " : "")
- << "int " << name << "=" << id <<";\n";
- }
-
- template <typename Iterator, typename FieldAccessorFunc>
- void addArrayMember(const StringPiece& name, AnnotationProcessor* processor,
- const Iterator begin, const Iterator end, FieldAccessorFunc f) {
- ensureClassDeclaration();
- if (processor) {
- processor->writeToStream(&mOut, kIndent);
- }
- mOut << kIndent << "public static final int[] " << name << "={";
-
- for (Iterator current = begin; current != end; ++current) {
- if (std::distance(begin, current) % kAttribsPerLine == 0) {
- mOut << "\n" << kIndent << kIndent;
- }
-
- mOut << f(*current);
- if (std::distance(current, end) > 1) {
- mOut << ", ";
- }
- }
- mOut << "\n" << kIndent <<"};\n";
- }
-
- void writeToStream(std::ostream* out, const StringPiece& prefix,
- AnnotationProcessor* processor=nullptr) {
- if (mOptions.forceCreationIfEmpty) {
- ensureClassDeclaration();
- }
-
- if (!mStarted) {
- return;
- }
-
- if (processor) {
- processor->writeToStream(out, prefix);
- }
-
- std::string result = mOut.str();
- for (StringPiece line : util::tokenize<char>(result, '\n')) {
- *out << prefix << line << "\n";
- }
- *out << prefix << "}\n";
- }
-
-private:
- constexpr static const char* kIndent = " ";
-
- // The number of attributes to emit per line in a Styleable array.
- constexpr static size_t kAttribsPerLine = 4;
-
- void ensureClassDeclaration() {
- if (!mStarted) {
- mStarted = true;
- mOut << "public static final class " << mName << " {\n";
- }
- }
-
- std::stringstream mOut;
- std::string mName;
- ClassDefinitionWriterOptions mOptions;
- bool mStarted;
-};
-
-} // namespace aapt
-
-#endif /* AAPT_JAVA_CLASSDEFINITION_H */
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index 01330dc..092bab24 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -21,7 +21,7 @@
#include "ValueVisitor.h"
#include "java/AnnotationProcessor.h"
-#include "java/ClassDefinitionWriter.h"
+#include "java/ClassDefinition.h"
#include "java/JavaClassGenerator.h"
#include "process/SymbolTable.h"
#include "util/StringPiece.h"
@@ -39,16 +39,6 @@
mContext(context), mTable(table), mOptions(options) {
}
-static void generateHeader(const StringPiece16& packageNameToGenerate, std::ostream* out) {
- *out << "/* AUTO-GENERATED FILE. DO NOT MODIFY.\n"
- " *\n"
- " * This class was automatically generated by the\n"
- " * aapt tool from the resource data it found. It\n"
- " * should not be modified by hand.\n"
- " */\n\n"
- "package " << packageNameToGenerate << ";\n\n";
-}
-
static const std::set<StringPiece16> sJavaIdentifiers = {
u"abstract", u"assert", u"boolean", u"break", u"byte",
u"case", u"catch", u"char", u"class", u"const", u"continue",
@@ -110,15 +100,15 @@
if (typeMask & android::ResTable_map::TYPE_REFERENCE) {
processor->appendComment(
"<p>May be a reference to another resource, in the form\n"
- "\"<code>@[+][<i>package</i>:]<i>type</i>/<i>name</i></code>\" or a theme\n"
- "attribute in the form\n"
- "\"<code>?[<i>package</i>:]<i>type</i>/<i>name</i></code>\".");
+ "\"<code>@[+][<i>package</i>:]<i>type</i>/<i>name</i></code>\" or a theme\n"
+ "attribute in the form\n"
+ "\"<code>?[<i>package</i>:]<i>type</i>/<i>name</i></code>\".");
}
if (typeMask & android::ResTable_map::TYPE_STRING) {
processor->appendComment(
"<p>May be a string value, using '\\\\;' to escape characters such as\n"
- "'\\\\n' or '\\\\uxxxx' for a unicode character;");
+ "'\\\\n' or '\\\\uxxxx' for a unicode character;");
}
if (typeMask & android::ResTable_map::TYPE_INTEGER) {
@@ -128,14 +118,14 @@
if (typeMask & android::ResTable_map::TYPE_BOOLEAN) {
processor->appendComment(
"<p>May be a boolean value, such as \"<code>true</code>\" or\n"
- "\"<code>false</code>\".");
+ "\"<code>false</code>\".");
}
if (typeMask & android::ResTable_map::TYPE_COLOR) {
processor->appendComment(
"<p>May be a color value, in the form of \"<code>#<i>rgb</i></code>\",\n"
- "\"<code>#<i>argb</i></code>\", \"<code>#<i>rrggbb</i></code\", or \n"
- "\"<code>#<i>aarrggbb</i></code>\".");
+ "\"<code>#<i>argb</i></code>\", \"<code>#<i>rrggbb</i></code\", or \n"
+ "\"<code>#<i>aarrggbb</i></code>\".");
}
if (typeMask & android::ResTable_map::TYPE_FLOAT) {
@@ -146,33 +136,33 @@
if (typeMask & android::ResTable_map::TYPE_DIMENSION) {
processor->appendComment(
"<p>May be a dimension value, which is a floating point number appended with a\n"
- "unit such as \"<code>14.5sp</code>\".\n"
- "Available units are: px (pixels), dp (density-independent pixels),\n"
- "sp (scaled pixels based on preferred font size), in (inches), and\n"
- "mm (millimeters).");
+ "unit such as \"<code>14.5sp</code>\".\n"
+ "Available units are: px (pixels), dp (density-independent pixels),\n"
+ "sp (scaled pixels based on preferred font size), in (inches), and\n"
+ "mm (millimeters).");
}
if (typeMask & android::ResTable_map::TYPE_FRACTION) {
processor->appendComment(
"<p>May be a fractional value, which is a floating point number appended with\n"
- "either % or %p, such as \"<code>14.5%</code>\".\n"
- "The % suffix always means a percentage of the base size;\n"
- "the optional %p suffix provides a size relative to some parent container.");
+ "either % or %p, such as \"<code>14.5%</code>\".\n"
+ "The % suffix always means a percentage of the base size;\n"
+ "the optional %p suffix provides a size relative to some parent container.");
}
if (typeMask & (android::ResTable_map::TYPE_FLAGS | android::ResTable_map::TYPE_ENUM)) {
if (typeMask & android::ResTable_map::TYPE_FLAGS) {
processor->appendComment(
"<p>Must be one or more (separated by '|') of the following "
- "constant values.</p>");
+ "constant values.</p>");
} else {
processor->appendComment("<p>Must be one of the following constant values.</p>");
}
processor->appendComment("<table>\n<colgroup align=\"left\" />\n"
- "<colgroup align=\"left\" />\n"
- "<colgroup align=\"left\" />\n"
- "<tr><th>Constant</th><th>Value</th><th>Description</th></tr>\n");
+ "<colgroup align=\"left\" />\n"
+ "<colgroup align=\"left\" />\n"
+ "<tr><th>Constant</th><th>Value</th><th>Description</th></tr>\n");
for (const Attribute::Symbol& symbol : attr->symbols) {
std::stringstream line;
line << "<tr><td>" << symbol.symbol.name.value().entry << "</td>"
@@ -214,13 +204,15 @@
}
}
-void JavaClassGenerator::writeStyleableEntryForClass(ClassDefinitionWriter* outClassDef,
- AnnotationProcessor* processor,
- const StringPiece16& packageNameToGenerate,
- const std::u16string& entryName,
- const Styleable* styleable) {
+void JavaClassGenerator::addMembersToStyleableClass(const StringPiece16& packageNameToGenerate,
+ const std::u16string& entryName,
+ const Styleable* styleable,
+ ClassDefinition* outStyleableClassDef) {
const std::string className = transform(entryName);
+ std::unique_ptr<ResourceArrayMember> styleableArrayDef =
+ util::make_unique<ResourceArrayMember>(className);
+
// This must be sorted by resource ID.
std::vector<StyleableAttr> sortedAttributes;
sortedAttributes.reserve(styleable->entries.size());
@@ -230,6 +222,8 @@
assert((!mOptions.useFinal || attr.id) && "no ID set for Styleable entry");
assert(attr.name && "no name set for Styleable entry");
+ // We will need the unmangled, transformed name in the comments and the field,
+ // so create it once and cache it in this StyleableAttr data structure.
StyleableAttr styleableAttr = {};
styleableAttr.attrRef = &attr;
styleableAttr.fieldName = transformNestedAttr(attr.name.value(), className,
@@ -247,6 +241,8 @@
mangledReference.name = mangledName;
}
+ // Look up the symbol so that we can write out in the comments what are possible
+ // legal values for this attribute.
const SymbolTable::Symbol* symbol = mContext->getExternalSymbols()->findByReference(
mangledReference);
if (symbol) {
@@ -254,10 +250,11 @@
}
sortedAttributes.push_back(std::move(styleableAttr));
}
+
+ // Sort the attributes by ID.
std::sort(sortedAttributes.begin(), sortedAttributes.end(), lessStyleableAttr);
const size_t attrCount = sortedAttributes.size();
-
if (attrCount > 0) {
// Build the comment string for the Styleable. It includes details about the
// child attributes.
@@ -267,6 +264,7 @@
} else {
styleableComment << "Attributes that can be used with a " << className << ".\n";
}
+
styleableComment <<
"<p>Includes the following attributes:</p>\n"
"<table>\n"
@@ -274,7 +272,7 @@
"<colgroup align=\"left\" />\n"
"<tr><th>Attribute</th><th>Description</th></tr>\n";
- for (const auto& entry : sortedAttributes) {
+ for (const StyleableAttr& entry : sortedAttributes) {
const ResourceName& attrName = entry.attrRef->name.value();
styleableComment << "<tr><td>";
styleableComment << "<code>{@link #"
@@ -292,21 +290,22 @@
styleableComment << "</td></tr>\n";
}
styleableComment << "</table>\n";
- for (const auto& entry : sortedAttributes) {
+
+ for (const StyleableAttr& entry : sortedAttributes) {
styleableComment << "@see #" << entry.fieldName << "\n";
}
- processor->appendComment(styleableComment.str());
+
+ styleableArrayDef->getCommentBuilder()->appendComment(styleableComment.str());
}
- auto accessorFunc = [](const StyleableAttr& a) -> ResourceId {
- return a.attrRef->id ? a.attrRef->id.value() : ResourceId(0);
- };
+ // Add the ResourceIds to the array member.
+ for (const StyleableAttr& styleableAttr : sortedAttributes) {
+ styleableArrayDef->addElement(
+ styleableAttr.attrRef->id ? styleableAttr.attrRef->id.value() : ResourceId(0));
+ }
- // First we emit the array containing the IDs of each attribute.
- outClassDef->addArrayMember(className, processor,
- sortedAttributes.begin(),
- sortedAttributes.end(),
- accessorFunc);
+ // Add the Styleable array to the Styleable class.
+ outStyleableClassDef->addMember(std::move(styleableArrayDef));
// Now we emit the indices into the array.
for (size_t i = 0; i < attrCount; i++) {
@@ -318,7 +317,10 @@
packageName = mContext->getCompilationPackage();
}
- AnnotationProcessor attrProcessor;
+ std::unique_ptr<IntMember> indexMember = util::make_unique<IntMember>(
+ sortedAttributes[i].fieldName, i);
+
+ AnnotationProcessor* attrProcessor = indexMember->getCommentBuilder();
StringPiece16 comment = styleableAttr.attrRef->getComment();
if (styleableAttr.attribute && comment.empty()) {
@@ -326,8 +328,8 @@
}
if (!comment.empty()) {
- attrProcessor.appendComment("<p>\n@attr description");
- attrProcessor.appendComment(comment);
+ attrProcessor->appendComment("<p>\n@attr description");
+ attrProcessor->appendComment(comment);
} else {
std::stringstream defaultComment;
defaultComment
@@ -335,27 +337,29 @@
<< "{@link " << packageName << ".R.attr#" << transform(attrName.entry) << "}\n"
<< "attribute's value can be found in the "
<< "{@link #" << className << "} array.";
- attrProcessor.appendComment(defaultComment.str());
+ attrProcessor->appendComment(defaultComment.str());
}
- attrProcessor.appendNewLine();
+ attrProcessor->appendNewLine();
if (styleableAttr.attribute) {
- addAttributeFormatDoc(&attrProcessor, styleableAttr.attribute.get());
- attrProcessor.appendNewLine();
+ addAttributeFormatDoc(attrProcessor, styleableAttr.attribute.get());
+ attrProcessor->appendNewLine();
}
std::stringstream doclavaName;
doclavaName << "@attr name " << packageName << ":" << attrName.entry;;
- attrProcessor.appendComment(doclavaName.str());
- outClassDef->addIntMember(sortedAttributes[i].fieldName, &attrProcessor, i);
+ attrProcessor->appendComment(doclavaName.str());
+
+ outStyleableClassDef->addMember(std::move(indexMember));
}
}
-bool JavaClassGenerator::writeEntriesForClass(ClassDefinitionWriter* outClassDef,
- const StringPiece16& packageNameToGenerate,
- const ResourceTablePackage* package,
- const ResourceTableType* type) {
+bool JavaClassGenerator::addMembersToTypeClass(const StringPiece16& packageNameToGenerate,
+ const ResourceTablePackage* package,
+ const ResourceTableType* type,
+ ClassDefinition* outTypeClassDef) {
+
for (const auto& entry : type->entries) {
if (skipSymbol(entry->symbolStatus.state)) {
continue;
@@ -389,33 +393,41 @@
return false;
}
- // Build the comments and annotations for this entry.
-
- AnnotationProcessor processor;
- if (entry->symbolStatus.state != SymbolState::kUndefined) {
- processor.appendComment(entry->symbolStatus.comment);
- }
-
- for (const auto& configValue : entry->values) {
- processor.appendComment(configValue->value->getComment());
- }
-
- // If this is an Attribute, append the format Javadoc.
- if (!entry->values.empty()) {
- if (Attribute* attr = valueCast<Attribute>(entry->values.front()->value.get())) {
- // We list out the available values for the given attribute.
- addAttributeFormatDoc(&processor, attr);
- }
- }
-
if (type->type == ResourceType::kStyleable) {
assert(!entry->values.empty());
+
const Styleable* styleable = static_cast<const Styleable*>(
entry->values.front()->value.get());
- writeStyleableEntryForClass(outClassDef, &processor, packageNameToGenerate,
- unmangledName, styleable);
+
+ // Comments are handled within this method.
+ addMembersToStyleableClass(packageNameToGenerate, unmangledName, styleable,
+ outTypeClassDef);
} else {
- outClassDef->addResourceMember(transform(unmangledName), &processor, id);
+ std::unique_ptr<ResourceMember> resourceMember =
+ util::make_unique<ResourceMember>(transform(unmangledName), id);
+
+ // Build the comments and annotations for this entry.
+ AnnotationProcessor* processor = resourceMember->getCommentBuilder();
+
+ // Add the comments from any <public> tags.
+ if (entry->symbolStatus.state != SymbolState::kUndefined) {
+ processor->appendComment(entry->symbolStatus.comment);
+ }
+
+ // Add the comments from all configurations of this entry.
+ for (const auto& configValue : entry->values) {
+ processor->appendComment(configValue->value->getComment());
+ }
+
+ // If this is an Attribute, append the format Javadoc.
+ if (!entry->values.empty()) {
+ if (Attribute* attr = valueCast<Attribute>(entry->values.front()->value.get())) {
+ // We list out the available values for the given attribute.
+ addAttributeFormatDoc(processor, attr);
+ }
+ }
+
+ outTypeClassDef->addMember(std::move(resourceMember));
}
}
return true;
@@ -425,11 +437,19 @@
return generate(packageNameToGenerate, packageNameToGenerate, out);
}
+static void appendJavaDocAnnotations(const std::vector<std::string>& annotations,
+ AnnotationProcessor* processor) {
+ for (const std::string& annotation : annotations) {
+ std::string properAnnotation = "@";
+ properAnnotation += annotation;
+ processor->appendComment(properAnnotation);
+ }
+}
+
bool JavaClassGenerator::generate(const StringPiece16& packageNameToGenerate,
const StringPiece16& outPackageName, std::ostream* out) {
- generateHeader(outPackageName, out);
- *out << "public final class R {\n";
+ ClassDefinition rClass("R", ClassQualifier::None, true);
for (const auto& package : mTable->packages) {
for (const auto& type : package->types) {
@@ -437,13 +457,15 @@
continue;
}
- ClassDefinitionWriterOptions classOptions;
- classOptions.useFinalQualifier = mOptions.useFinal;
- classOptions.forceCreationIfEmpty =
+ const bool forceCreationIfEmpty =
(mOptions.types == JavaClassGeneratorOptions::SymbolTypes::kPublic);
- ClassDefinitionWriter classDef(toString(type->type), classOptions);
- bool result = writeEntriesForClass(&classDef, packageNameToGenerate,
- package.get(), type.get());
+
+ std::unique_ptr<ClassDefinition> classDef = util::make_unique<ClassDefinition>(
+ util::utf16ToUtf8(toString(type->type)), ClassQualifier::Static,
+ forceCreationIfEmpty);
+
+ bool result = addMembersToTypeClass(packageNameToGenerate, package.get(), type.get(),
+ classDef.get());
if (!result) {
return false;
}
@@ -452,30 +474,36 @@
// Also include private attributes in this same class.
ResourceTableType* privType = package->findType(ResourceType::kAttrPrivate);
if (privType) {
- result = writeEntriesForClass(&classDef, packageNameToGenerate,
- package.get(), privType);
+ result = addMembersToTypeClass(packageNameToGenerate, package.get(), privType,
+ classDef.get());
if (!result) {
return false;
}
}
}
- AnnotationProcessor processor;
if (type->type == ResourceType::kStyleable &&
mOptions.types == JavaClassGeneratorOptions::SymbolTypes::kPublic) {
// When generating a public R class, we don't want Styleable to be part of the API.
// It is only emitted for documentation purposes.
- processor.appendComment("@doconly");
+ classDef->getCommentBuilder()->appendComment("@doconly");
}
- classDef.writeToStream(out, " ", &processor);
+
+ appendJavaDocAnnotations(mOptions.javadocAnnotations, classDef->getCommentBuilder());
+
+ rClass.addMember(std::move(classDef));
}
}
- *out << "}\n";
+ appendJavaDocAnnotations(mOptions.javadocAnnotations, rClass.getCommentBuilder());
+
+ if (!ClassDefinition::writeJavaFile(&rClass, util::utf16ToUtf8(outPackageName),
+ mOptions.useFinal, out)) {
+ return false;
+ }
+
out->flush();
return true;
}
-
-
} // namespace aapt
diff --git a/tools/aapt2/java/JavaClassGenerator.h b/tools/aapt2/java/JavaClassGenerator.h
index 7e46f8c..77e0ed7 100644
--- a/tools/aapt2/java/JavaClassGenerator.h
+++ b/tools/aapt2/java/JavaClassGenerator.h
@@ -28,7 +28,7 @@
namespace aapt {
class AnnotationProcessor;
-class ClassDefinitionWriter;
+class ClassDefinition;
struct JavaClassGeneratorOptions {
/*
@@ -44,6 +44,11 @@
};
SymbolTypes types = SymbolTypes::kAll;
+
+ /**
+ * A list of JavaDoc annotations to add to the comments of all generated classes.
+ */
+ std::vector<std::string> javadocAnnotations;
};
/*
@@ -70,16 +75,15 @@
const std::string& getError() const;
private:
- bool writeEntriesForClass(ClassDefinitionWriter* outClassDef,
- const StringPiece16& packageNameToGenerate,
- const ResourceTablePackage* package,
- const ResourceTableType* type);
+ bool addMembersToTypeClass(const StringPiece16& packageNameToGenerate,
+ const ResourceTablePackage* package,
+ const ResourceTableType* type,
+ ClassDefinition* outTypeClassDef);
- void writeStyleableEntryForClass(ClassDefinitionWriter* outClassDef,
- AnnotationProcessor* processor,
- const StringPiece16& packageNameToGenerate,
- const std::u16string& entryName,
- const Styleable* styleable);
+ void addMembersToStyleableClass(const StringPiece16& packageNameToGenerate,
+ const std::u16string& entryName,
+ const Styleable* styleable,
+ ClassDefinition* outStyleableClassDef);
bool skipSymbol(SymbolState state);
diff --git a/tools/aapt2/java/ManifestClassGenerator.cpp b/tools/aapt2/java/ManifestClassGenerator.cpp
index a9b4c14..be8955e 100644
--- a/tools/aapt2/java/ManifestClassGenerator.cpp
+++ b/tools/aapt2/java/ManifestClassGenerator.cpp
@@ -16,7 +16,7 @@
#include "Source.h"
#include "java/AnnotationProcessor.h"
-#include "java/ClassDefinitionWriter.h"
+#include "java/ClassDefinition.h"
#include "java/ManifestClassGenerator.h"
#include "util/Maybe.h"
#include "xml/XmlDom.h"
@@ -58,8 +58,8 @@
return result;
}
-static bool writeSymbol(IDiagnostics* diag, ClassDefinitionWriter* outClassDef, const Source& source,
- xml::Element* el) {
+static bool writeSymbol(const Source& source, IDiagnostics* diag, xml::Element* el,
+ ClassDefinition* classDef) {
xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, u"name");
if (!attr) {
diag->error(DiagMessage(source) << "<" << el->name << "> must define 'android:name'");
@@ -72,54 +72,53 @@
return false;
}
- AnnotationProcessor processor;
- processor.appendComment(el->comment);
- outClassDef->addStringMember(result.value(), &processor, attr->value);
+ std::unique_ptr<StringMember> stringMember = util::make_unique<StringMember>(
+ util::utf16ToUtf8(result.value()), util::utf16ToUtf8(attr->value));
+ stringMember->getCommentBuilder()->appendComment(el->comment);
+
+ classDef->addMember(std::move(stringMember));
return true;
}
-bool ManifestClassGenerator::generate(IDiagnostics* diag, const StringPiece16& package,
- xml::XmlResource* res, std::ostream* out) {
+std::unique_ptr<ClassDefinition> generateManifestClass(IDiagnostics* diag, xml::XmlResource* res) {
xml::Element* el = xml::findRootElement(res->root.get());
if (!el) {
- return false;
+ diag->error(DiagMessage(res->file.source) << "no root tag defined");
+ return {};
}
if (el->name != u"manifest" && !el->namespaceUri.empty()) {
diag->error(DiagMessage(res->file.source) << "no <manifest> root tag defined");
- return false;
+ return {};
}
- *out << "package " << package << ";\n\n"
- << "public final class Manifest {\n";
+ std::unique_ptr<ClassDefinition> permissionClass =
+ util::make_unique<ClassDefinition>("permission", ClassQualifier::Static, false);
+ std::unique_ptr<ClassDefinition> permissionGroupClass =
+ util::make_unique<ClassDefinition>("permission_group", ClassQualifier::Static, false);
bool error = false;
+
std::vector<xml::Element*> children = el->getChildElements();
-
- ClassDefinitionWriterOptions classOptions;
- classOptions.useFinalQualifier = true;
- classOptions.forceCreationIfEmpty = false;
-
- // First write out permissions.
- ClassDefinitionWriter classDef("permission", classOptions);
for (xml::Element* childEl : children) {
- if (childEl->namespaceUri.empty() && childEl->name == u"permission") {
- error |= !writeSymbol(diag, &classDef, res->file.source, childEl);
+ if (childEl->namespaceUri.empty()) {
+ if (childEl->name == u"permission") {
+ error |= !writeSymbol(res->file.source, diag, childEl, permissionClass.get());
+ } else if (childEl->name == u"permission-group") {
+ error |= !writeSymbol(res->file.source, diag, childEl, permissionGroupClass.get());
+ }
}
}
- classDef.writeToStream(out, " ");
- // Next write out permission groups.
- classDef = ClassDefinitionWriter("permission_group", classOptions);
- for (xml::Element* childEl : children) {
- if (childEl->namespaceUri.empty() && childEl->name == u"permission-group") {
- error |= !writeSymbol(diag, &classDef, res->file.source, childEl);
- }
+ if (error) {
+ return {};
}
- classDef.writeToStream(out, " ");
- *out << "}\n";
- return !error;
+ std::unique_ptr<ClassDefinition> manifestClass =
+ util::make_unique<ClassDefinition>("Manifest", ClassQualifier::None, false);
+ manifestClass->addMember(std::move(permissionClass));
+ manifestClass->addMember(std::move(permissionGroupClass));
+ return manifestClass;
}
} // namespace aapt
diff --git a/tools/aapt2/java/ManifestClassGenerator.h b/tools/aapt2/java/ManifestClassGenerator.h
index 226ed23..f565289 100644
--- a/tools/aapt2/java/ManifestClassGenerator.h
+++ b/tools/aapt2/java/ManifestClassGenerator.h
@@ -18,6 +18,7 @@
#define AAPT_JAVA_MANIFESTCLASSGENERATOR_H
#include "Diagnostics.h"
+#include "java/ClassDefinition.h"
#include "util/StringPiece.h"
#include "xml/XmlDom.h"
@@ -25,10 +26,7 @@
namespace aapt {
-struct ManifestClassGenerator {
- bool generate(IDiagnostics* diag, const StringPiece16& package, xml::XmlResource* res,
- std::ostream* out);
-};
+std::unique_ptr<ClassDefinition> generateManifestClass(IDiagnostics* diag, xml::XmlResource* res);
} // namespace aapt
diff --git a/tools/aapt2/java/ManifestClassGenerator_test.cpp b/tools/aapt2/java/ManifestClassGenerator_test.cpp
index fc57ae6f..a9ec318 100644
--- a/tools/aapt2/java/ManifestClassGenerator_test.cpp
+++ b/tools/aapt2/java/ManifestClassGenerator_test.cpp
@@ -22,6 +22,23 @@
namespace aapt {
+static ::testing::AssertionResult getManifestClassText(IAaptContext* context, xml::XmlResource* res,
+ std::string* outStr) {
+ std::unique_ptr<ClassDefinition> manifestClass = generateManifestClass(
+ context->getDiagnostics(), res);
+ if (!manifestClass) {
+ return ::testing::AssertionFailure() << "manifestClass == nullptr";
+ }
+
+ std::stringstream out;
+ if (!manifestClass->writeJavaFile(manifestClass.get(), "android", true, &out)) {
+ return ::testing::AssertionFailure() << "failed to write java file";
+ }
+
+ *outStr = out.str();
+ return ::testing::AssertionSuccess();
+}
+
TEST(ManifestClassGeneratorTest, NameIsProperlyGeneratedFromSymbol) {
std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
std::unique_ptr<xml::XmlResource> manifest = test::buildXmlDom(R"EOF(
@@ -32,11 +49,8 @@
<permission-group android:name="foo.bar.PERMISSION" />
</manifest>)EOF");
- std::stringstream out;
- ManifestClassGenerator generator;
- ASSERT_TRUE(generator.generate(context->getDiagnostics(), u"android", manifest.get(), &out));
-
- std::string actual = out.str();
+ std::string actual;
+ ASSERT_TRUE(getManifestClassText(context.get(), manifest.get(), &actual));
const size_t permissionClassPos = actual.find("public static final class permission {");
const size_t permissionGroupClassPos =
@@ -87,11 +101,8 @@
<permission android:name="android.permission.SECRET" />
</manifest>)EOF");
- std::stringstream out;
- ManifestClassGenerator generator;
- ASSERT_TRUE(generator.generate(context->getDiagnostics(), u"android", manifest.get(), &out));
-
- std::string actual = out.str();
+ std::string actual;
+ ASSERT_TRUE(getManifestClassText(context.get(), manifest.get(), &actual));
EXPECT_NE(std::string::npos, actual.find(
R"EOF( /**
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index b84074d..8c8bffa 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -66,6 +66,7 @@
bool staticLib = false;
bool noStaticLibPackages = false;
bool generateNonFinalIds = false;
+ std::vector<std::string> javadocAnnotations;
bool outputToDirectory = false;
bool autoAddOverlay = false;
bool doNotCompressAnything = false;
@@ -762,9 +763,31 @@
return true;
}
+ std::unique_ptr<ClassDefinition> manifestClass = generateManifestClass(
+ mContext->getDiagnostics(), manifestXml);
+
+ if (!manifestClass) {
+ // Something bad happened, but we already logged it, so exit.
+ return false;
+ }
+
+ if (manifestClass->empty()) {
+ // Empty Manifest class, no need to generate it.
+ return true;
+ }
+
+ // Add any JavaDoc annotations to the generated class.
+ for (const std::string& annotation : mOptions.javadocAnnotations) {
+ std::string properAnnotation = "@";
+ properAnnotation += annotation;
+ manifestClass->getCommentBuilder()->appendComment(properAnnotation);
+ }
+
+ const std::string packageUtf8 = util::utf16ToUtf8(mContext->getCompilationPackage());
+
std::string outPath = mOptions.generateJavaClassPath.value();
- file::appendPath(&outPath,
- file::packageToPath(util::utf16ToUtf8(mContext->getCompilationPackage())));
+ file::appendPath(&outPath, file::packageToPath(packageUtf8));
+
if (!file::mkdirs(outPath)) {
mContext->getDiagnostics()->error(
DiagMessage() << "failed to create directory '" << outPath << "'");
@@ -780,13 +803,7 @@
return false;
}
- ManifestClassGenerator generator;
- if (!generator.generate(mContext->getDiagnostics(), mContext->getCompilationPackage(),
- manifestXml, &fout)) {
- return false;
- }
-
- if (!fout) {
+ if (!ClassDefinition::writeJavaFile(manifestClass.get(), packageUtf8, true, &fout)) {
mContext->getDiagnostics()->error(
DiagMessage() << "failed writing to '" << outPath << "': " << strerror(errno));
return false;
@@ -1283,6 +1300,7 @@
if (mOptions.generateJavaClassPath) {
JavaClassGeneratorOptions options;
options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
+ options.javadocAnnotations = mOptions.javadocAnnotations;
if (mOptions.staticLib || mOptions.generateNonFinalIds) {
options.useFinal = false;
@@ -1423,6 +1441,8 @@
&customJavaPackage)
.optionalFlagList("--extra-packages", "Generate the same R.java but with different "
"package names", &extraJavaPackages)
+ .optionalFlagList("--add-javadoc-annotation", "Adds a JavaDoc annotation to all "
+ "generated Java classes", &options.javadocAnnotations)
.optionalSwitch("--auto-add-overlay", "Allows the addition of new resources in "
"overlays without <add-resource> tags", &options.autoAddOverlay)
.optionalFlag("--rename-manifest-package", "Renames the package in AndroidManifest.xml",
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index 75e837b..b5ed1b5 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -177,9 +177,10 @@
def check_emoji_availability():
emoji_fonts = [font[5] for font in _fallback_chain if 'Zsye' in font[1]]
+ assert len(emoji_fonts) == 1, 'There are %d emoji fonts.' % len(emoji_fonts)
+ emoji_font = emoji_fonts[0]
emoji_chars = _emoji_properties['Emoji']
- for emoji_font in emoji_fonts:
- assert_font_supports_all_of_chars(emoji_font, emoji_chars)
+ assert_font_supports_all_of_chars(emoji_font, emoji_chars)
def check_emoji_defaults():
@@ -273,11 +274,12 @@
hyphens_dir = path.join(target_out, 'usr', 'hyphen-data')
check_hyphens(hyphens_dir)
- ucd_path = sys.argv[2]
- parse_ucd(ucd_path)
- # Temporarily disable emoji checks for Bug 27785690
- # check_emoji_availability()
- # check_emoji_defaults()
+ check_emoji = sys.argv[2]
+ if check_emoji == 'true':
+ ucd_path = sys.argv[3]
+ parse_ucd(ucd_path)
+ check_emoji_availability()
+ check_emoji_defaults()
if __name__ == '__main__':
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index f5938cf..265ebd1 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -423,21 +423,13 @@
}
@LayoutlibDelegate
- /*package*/ static void native_offset(long nPath, float dx, float dy, long dst_path) {
+ /*package*/ static void native_offset(long nPath, float dx, float dy) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
}
- // could be null if the int is 0;
- Path_Delegate dstDelegate = sManager.getDelegate(dst_path);
-
- pathDelegate.offset(dx, dy, dstDelegate);
- }
-
- @LayoutlibDelegate
- /*package*/ static void native_offset(long nPath, float dx, float dy) {
- native_offset(nPath, dx, dy, 0);
+ pathDelegate.offset(dx, dy);
}
@LayoutlibDelegate
@@ -860,21 +852,14 @@
*
* @param dx The amount in the X direction to offset the entire path
* @param dy The amount in the Y direction to offset the entire path
- * @param dst The translated path is written here. If this is null, then
- * the original path is modified.
*/
- public void offset(float dx, float dy, Path_Delegate dst) {
+ public void offset(float dx, float dy) {
GeneralPath newPath = new GeneralPath();
PathIterator iterator = mPath.getPathIterator(new AffineTransform(0, 0, dx, 0, 0, dy));
newPath.append(iterator, false /*connect*/);
-
- if (dst != null) {
- dst.mPath = newPath;
- } else {
- mPath = newPath;
- }
+ mPath = newPath;
}
/**
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 309c1b8..f9e008e 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -403,8 +403,15 @@
}
@Override
- public void setNewConfiguration(Configuration arg0) throws RemoteException {
+ public int[] setNewConfiguration(Configuration arg0) throws RemoteException {
// TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Rect getBoundsForNewConfiguration(int stackId) throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
}
@Override
@@ -575,4 +582,10 @@
@Override
public void registerShortcutKey(long shortcutCode, IShortcutService service)
throws RemoteException {}
+
+ @Override
+ public void createWallpaperInputConsumer(InputChannel inputChannel) throws RemoteException {}
+
+ @Override
+ public void removeWallpaperInputConsumer() throws RemoteException {}
}
diff --git a/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java b/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java
index 1465f50..24f7887 100644
--- a/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java
@@ -55,7 +55,7 @@
private String mName;
@LayoutlibDelegate
- /*package*/ static long nCreate(String name) {
+ /*package*/ static long nCreate(RenderNode thisRenderNode, String name) {
RenderNode_Delegate renderNodeDelegate = new RenderNode_Delegate();
renderNodeDelegate.mName = name;
return sManager.addNewDelegate(renderNodeDelegate);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index c8e3d03..9e50ee8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -24,6 +24,7 @@
import com.android.ide.common.rendering.api.Result;
import com.android.ide.common.rendering.api.Result.Status;
import com.android.ide.common.rendering.api.SessionParams;
+import com.android.layoutlib.bridge.android.RenderParamsFlags;
import com.android.layoutlib.bridge.impl.RenderDrawable;
import com.android.layoutlib.bridge.impl.RenderSessionImpl;
import com.android.layoutlib.bridge.util.DynamicIdMap;
@@ -408,7 +409,9 @@
/**
* Starts a layout session by inflating and rendering it. The method returns a
* {@link RenderSession} on which further actions can be taken.
- *
+ * <p/>
+ * If {@link SessionParams} includes the {@link RenderParamsFlags#FLAG_DO_NOT_RENDER_ON_CREATE},
+ * this method will only inflate the layout but will NOT render it.
* @param params the {@link SessionParams} object with all the information necessary to create
* the scene.
* @return a new {@link RenderSession} object that contains the result of the layout.
@@ -424,7 +427,10 @@
lastResult = scene.init(params.getTimeout());
if (lastResult.isSuccess()) {
lastResult = scene.inflate();
- if (lastResult.isSuccess()) {
+
+ boolean doNotRenderOnCreate = Boolean.TRUE.equals(
+ params.getFlag(RenderParamsFlags.FLAG_DO_NOT_RENDER_ON_CREATE));
+ if (lastResult.isSuccess() && !doNotRenderOnCreate) {
lastResult = scene.render(true /*freshRender*/);
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java
index bd17a2f..051de90 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java
@@ -53,6 +53,12 @@
*/
public static final Key<Boolean> FLAG_KEY_XML_FILE_PARSER_SUPPORT =
new Key<Boolean>("xmlFileParser", Boolean.class);
+ /**
+ * To tell LayoutLib to not render when creating a new session. This allows controlling when the first
+ * layout rendering will happen.
+ */
+ public static final Key<Boolean> FLAG_DO_NOT_RENDER_ON_CREATE =
+ new Key<Boolean>("doNotRenderOnCreate", Boolean.class);
// Disallow instances.
private RenderParamsFlags() {}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 016825a..ce7104e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -267,6 +267,34 @@
}
/**
+ * Renders the given view hierarchy to the passed canvas and returns the result of the render
+ * operation.
+ * @param canvas an optional canvas to render the views to. If null, only the measure and
+ * layout steps will be executed.
+ */
+ private static Result render(@NonNull BridgeContext context, @NonNull ViewGroup viewRoot,
+ @Nullable Canvas canvas, int width, int height) {
+ // measure again with the size we need
+ // This must always be done before the call to layout
+ measureView(viewRoot, null /*measuredView*/,
+ width, MeasureSpec.EXACTLY,
+ height, MeasureSpec.EXACTLY);
+
+ // now do the layout.
+ viewRoot.layout(0, 0, width, height);
+ handleScrolling(context, viewRoot);
+
+ if (canvas == null) {
+ return SUCCESS.createResult();
+ }
+
+ AttachInfo_Accessor.dispatchOnPreDraw(viewRoot);
+ viewRoot.draw(canvas);
+
+ return SUCCESS.createResult();
+ }
+
+ /**
* Renders the scene.
* <p>
* {@link #acquire(long)} must have been called before this.
@@ -367,24 +395,12 @@
}
}
- // measure again with the size we need
- // This must always be done before the call to layout
- measureView(mViewRoot, null /*measuredView*/,
- mMeasuredScreenWidth, MeasureSpec.EXACTLY,
- mMeasuredScreenHeight, MeasureSpec.EXACTLY);
-
- // now do the layout.
- mViewRoot.layout(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
-
- handleScrolling(mViewRoot);
-
+ Result renderResult = SUCCESS.createResult();
if (params.isLayoutOnly()) {
// delete the canvas and image to reset them on the next full rendering
mImage = null;
mCanvas = null;
} else {
- AttachInfo_Accessor.dispatchOnPreDraw(mViewRoot);
-
// draw the views
// create the BufferedImage into which the layout will be rendered.
boolean newImage = false;
@@ -446,6 +462,9 @@
if (mElapsedFrameTimeNanos >= 0) {
long initialTime = System_Delegate.nanoTime();
if (!mFirstFrameExecuted) {
+ // We need to run an initial draw call to initialize the animations
+ render(getContext(), mViewRoot, mCanvas, 0, 0);
+
// The first frame will initialize the animations
Choreographer_Delegate.doFrame(initialTime);
mFirstFrameExecuted = true;
@@ -453,14 +472,15 @@
// Second frame will move the animations
Choreographer_Delegate.doFrame(initialTime + mElapsedFrameTimeNanos);
}
- mViewRoot.draw(mCanvas);
+ renderResult = render(getContext(), mViewRoot, mCanvas, mMeasuredScreenWidth,
+ mMeasuredScreenHeight);
}
mSystemViewInfoList = visitAllChildren(mViewRoot, 0, params.getExtendedViewInfoMode(),
false);
// success!
- return SUCCESS.createResult();
+ return renderResult;
} catch (Throwable e) {
// get the real cause of the exception.
Throwable t = e;
@@ -488,7 +508,7 @@
* @return the measured width/height if measuredView is non-null, null otherwise.
*/
@SuppressWarnings("deprecation") // For the use of Pair
- private Pair<Integer, Integer> measureView(ViewGroup viewToMeasure, View measuredView,
+ private static Pair<Integer, Integer> measureView(ViewGroup viewToMeasure, View measuredView,
int width, int widthMode, int height, int heightMode) {
int w_spec = MeasureSpec.makeMeasureSpec(width, widthMode);
int h_spec = MeasureSpec.makeMeasureSpec(height, heightMode);
@@ -1061,8 +1081,7 @@
* the component supports nested scrolling attempt that first, then use the unconsumed scroll
* part to scroll the content in the component.
*/
- private void handleScrolling(View view) {
- BridgeContext context = getContext();
+ private static void handleScrolling(BridgeContext context, View view) {
int scrollPosX = context.getScrollXPos(view);
int scrollPosY = context.getScrollYPos(view);
if (scrollPosX != 0 || scrollPosY != 0) {
@@ -1080,7 +1099,7 @@
}
}
if (scrollPosX != 0 || scrollPosY != 0) {
- view.scrollBy(scrollPosX, scrollPosY);
+ view.scrollTo(scrollPosX, scrollPosY);
}
}
@@ -1090,7 +1109,7 @@
ViewGroup group = (ViewGroup) view;
for (int i = 0; i < group.getChildCount(); i++) {
View child = group.getChildAt(i);
- handleScrolling(child);
+ handleScrolling(context, child);
}
}
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/scrolled.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/scrolled.xml
index a5ebc2e..a07498c 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/scrolled.xml
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/scrolled.xml
@@ -2,8 +2,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:scrollX="10px"
- android:scrollY="30px">
+ android:scrollX="30px"
+ android:scrollY="90px">
<LinearLayout
android:layout_width="60dp"
android:layout_height="60dp"
@@ -29,8 +29,8 @@
android:layout_width="200dp"
android:layout_height="400dp"
android:orientation="vertical"
- android:scrollX="-30px"
- android:scrollY="150px">
+ android:scrollX="-90px"
+ android:scrollY="450px">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="60dp"
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
index 09dd5f0..034c8b2 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
@@ -30,6 +30,7 @@
import com.android.io.FolderWrapper;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.android.RenderParamsFlags;
import com.android.layoutlib.bridge.impl.RenderAction;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.layoutlib.bridge.intensive.setup.ConfigGenerator;
@@ -564,7 +565,7 @@
sFrameworkRepo.getConfiguredResources(config),
themeName, isProjectTheme);
- return new SessionParams(
+ SessionParams sessionParams = new SessionParams(
layoutParser,
renderingMode,
null /*used for caching*/,
@@ -574,6 +575,8 @@
0,
targetSdk,
getLayoutLog());
+ sessionParams.setFlag(RenderParamsFlags.FLAG_DO_NOT_RENDER_ON_CREATE, true);
+ return sessionParams;
}
private static LayoutLog getLayoutLog() {