Merge "Add a resource for demo mode launcher component name." into nyc-mr1-dev
diff --git a/Android.mk b/Android.mk
index 2b248d4..320fe2f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -318,6 +318,7 @@
core/java/com/android/internal/appwidget/IAppWidgetHost.aidl \
core/java/com/android/internal/backup/IBackupTransport.aidl \
core/java/com/android/internal/backup/IObbBackupService.aidl \
+ core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl \
core/java/com/android/internal/policy/IKeyguardDrawnCallback.aidl \
core/java/com/android/internal/policy/IKeyguardExitCallback.aidl \
core/java/com/android/internal/policy/IKeyguardService.aidl \
@@ -1120,6 +1121,9 @@
-showAnnotation android.annotation.SystemApi \
-title "Android SDK - Including system APIs." \
-toroot / \
+ -hide 101 \
+ -hide 104 \
+ -hide 108 \
-hdf android.whichdoc online \
$(sample_groups) \
-hdf android.hasSamples true \
diff --git a/api/current.txt b/api/current.txt
index ae6a8bc..c5665a4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -397,6 +397,7 @@
field public static final int colorPressedHighlight = 16843661; // 0x101038d
field public static final int colorPrimary = 16843827; // 0x1010433
field public static final int colorPrimaryDark = 16843828; // 0x1010434
+ field public static final int colorSecondary = 16844080; // 0x1010530
field public static final int columnCount = 16843639; // 0x1010377
field public static final int columnDelay = 16843215; // 0x10101cf
field public static final int columnOrderPreserved = 16843640; // 0x1010378
@@ -420,9 +421,9 @@
field public static final int contentInsetStart = 16843859; // 0x1010453
field public static final int contentInsetStartWithNavigation = 16844066; // 0x1010522
field public static final int contextClickable = 16844007; // 0x10104e7
- field public static final int contextDescription = 16844082; // 0x1010532
+ field public static final int contextDescription = 16844078; // 0x101052e
field public static final int contextPopupMenuStyle = 16844033; // 0x1010501
- field public static final int contextUri = 16844081; // 0x1010531
+ field public static final int contextUri = 16844077; // 0x101052d
field public static final int controlX1 = 16843772; // 0x10103fc
field public static final int controlX2 = 16843774; // 0x10103fe
field public static final int controlY1 = 16843773; // 0x10103fd
@@ -1041,7 +1042,7 @@
field public static final int rotation = 16843558; // 0x1010326
field public static final int rotationX = 16843559; // 0x1010327
field public static final int rotationY = 16843560; // 0x1010328
- field public static final int roundIcon = 16844080; // 0x1010530
+ field public static final int roundIcon = 16844076; // 0x101052c
field public static final int rowCount = 16843637; // 0x1010375
field public static final int rowDelay = 16843216; // 0x10101d0
field public static final int rowEdgeFlags = 16843329; // 0x1010241
@@ -1109,20 +1110,16 @@
field public static final int shareInterpolator = 16843195; // 0x10101bb
field public static final int sharedUserId = 16842763; // 0x101000b
field public static final int sharedUserLabel = 16843361; // 0x1010261
- field public static final int shortcutCategories = 16844077; // 0x101052d
- field public static final int shortcutDisabledMessage = 16844076; // 0x101052c
- field public static final int shortcutIcon = 16844073; // 0x1010529
+ field public static final int shortcutDisabledMessage = 16844075; // 0x101052b
field public static final int shortcutId = 16844072; // 0x1010528
- field public static final int shortcutIntentAction = 16844078; // 0x101052e
- field public static final int shortcutIntentData = 16844079; // 0x101052f
- field public static final int shortcutLongLabel = 16844075; // 0x101052b
- field public static final int shortcutShortLabel = 16844074; // 0x101052a
+ field public static final int shortcutLongLabel = 16844074; // 0x101052a
+ field public static final int shortcutShortLabel = 16844073; // 0x1010529
field public static final int shouldDisableView = 16843246; // 0x10101ee
field public static final int showAsAction = 16843481; // 0x10102d9
field public static final int showDefault = 16843258; // 0x10101fa
field public static final int showDividers = 16843561; // 0x1010329
field public static final int showForAllUsers = 16844015; // 0x10104ef
- field public static final int showMetadataInPreview = 16844083; // 0x1010533
+ field public static final int showMetadataInPreview = 16844079; // 0x101052f
field public static final deprecated int showOnLockScreen = 16843721; // 0x10103c9
field public static final int showSilent = 16843259; // 0x10101fb
field public static final int showText = 16843949; // 0x10104ad
@@ -9522,8 +9519,6 @@
method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
method public android.graphics.drawable.Drawable getShortcutIconDrawable(android.content.pm.ShortcutInfo, int);
- method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo);
- method public android.os.ParcelFileDescriptor getShortcutIconFd(java.lang.String, java.lang.String, android.os.UserHandle);
method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
method public boolean hasShortcutHostPermission();
method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
@@ -9558,10 +9553,10 @@
method public android.content.pm.LauncherApps.ShortcutQuery setPackage(java.lang.String);
method public android.content.pm.LauncherApps.ShortcutQuery setQueryFlags(int);
method public android.content.pm.LauncherApps.ShortcutQuery setShortcutIds(java.util.List<java.lang.String>);
- field public static final int FLAG_GET_DYNAMIC = 1; // 0x1
field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
- field public static final int FLAG_GET_MANIFEST = 8; // 0x8
- field public static final int FLAG_GET_PINNED = 2; // 0x2
+ field public static final int FLAG_MATCH_DYNAMIC = 1; // 0x1
+ field public static final int FLAG_MATCH_MANIFEST = 8; // 0x8
+ field public static final int FLAG_MATCH_PINNED = 2; // 0x2
}
public class PackageInfo implements android.os.Parcelable {
@@ -10069,7 +10064,6 @@
method public java.lang.CharSequence getDisabledMessage();
method public int getDisabledMessageResourceId();
method public android.os.PersistableBundle getExtras();
- method public int getIconResourceId();
method public java.lang.String getId();
method public android.content.Intent getIntent();
method public long getLastChangedTimestamp();
@@ -10080,14 +10074,11 @@
method public java.lang.CharSequence getShortLabel();
method public int getShortLabelResourceId();
method public android.os.UserHandle getUserHandle();
- method public boolean hasIconFile();
- method public boolean hasIconResource();
method public boolean hasKeyFieldsOnly();
- method public boolean hasStringResourcesResolved();
+ method public boolean isDeclaredInManifest();
method public boolean isDynamic();
method public boolean isEnabled();
method public boolean isImmutable();
- method public boolean isManifestShortcut();
method public boolean isPinned();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR;
@@ -10095,18 +10086,19 @@
}
public static class ShortcutInfo.Builder {
- ctor public ShortcutInfo.Builder(android.content.Context);
+ ctor public deprecated ShortcutInfo.Builder(android.content.Context);
+ ctor public ShortcutInfo.Builder(android.content.Context, java.lang.String);
method public android.content.pm.ShortcutInfo build();
method public android.content.pm.ShortcutInfo.Builder setActivity(android.content.ComponentName);
method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
- method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.String);
+ method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.CharSequence);
method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
- method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
+ method public deprecated android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
- method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.String);
+ method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.CharSequence);
method public android.content.pm.ShortcutInfo.Builder setRank(int);
- method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.String);
+ method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.CharSequence);
}
public class ShortcutManager {
@@ -18866,6 +18858,7 @@
public class InputMethodService extends android.inputmethodservice.AbstractInputMethodService {
ctor public InputMethodService();
method public deprecated boolean enableHardwareAcceleration();
+ method public final boolean exposeContent(android.view.inputmethod.InputContentInfo, android.view.inputmethod.EditorInfo);
method public int getBackDisposition();
method public int getCandidatesHiddenVisibility();
method public android.view.inputmethod.InputBinding getCurrentInputBinding();
@@ -32481,6 +32474,7 @@
field public static final java.lang.String DATA_ROAMING = "data_roaming";
field public static final java.lang.String DEBUG_APP = "debug_app";
field public static final java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
+ field public static final java.lang.String DEVICE_NAME = "device_name";
field public static final java.lang.String DEVICE_PROVISIONED = "device_provisioned";
field public static final java.lang.String HTTP_PROXY = "http_proxy";
field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
@@ -33066,6 +33060,7 @@
field public static final java.lang.String ACTION_NEW_VOICEMAIL = "android.intent.action.NEW_VOICEMAIL";
field public static final java.lang.String ACTION_SYNC_VOICEMAIL = "android.provider.action.SYNC_VOICEMAIL";
field public static final java.lang.String AUTHORITY = "com.android.voicemail";
+ field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.provider.extra.PHONE_ACCOUNT_HANDLE";
field public static final java.lang.String EXTRA_SELF_CHANGE = "com.android.voicemail.extra.SELF_CHANGE";
field public static final java.lang.String PARAM_KEY_SOURCE_PACKAGE = "source_package";
}
@@ -33074,6 +33069,9 @@
method public static android.net.Uri buildSourceUri(java.lang.String);
field public static final java.lang.String CONFIGURATION_STATE = "configuration_state";
field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2
+ field public static final int CONFIGURATION_STATE_CONFIGURING = 3; // 0x3
+ field public static final int CONFIGURATION_STATE_DISABLED = 5; // 0x5
+ field public static final int CONFIGURATION_STATE_FAILED = 4; // 0x4
field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1
field public static final int CONFIGURATION_STATE_OK = 0; // 0x0
field public static final android.net.Uri CONTENT_URI;
@@ -36319,6 +36317,7 @@
field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
field public static final java.lang.String EVENT_CALL_MERGE_FAILED = "android.telecom.event.CALL_MERGE_FAILED";
field public static final java.lang.String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
+ field public static final java.lang.String EXTRA_ANSWERING_DROPS_FG_CALL = "android.telecom.extra.ANSWERING_DROPS_FG_CALL";
field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
field public static final java.lang.String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
@@ -36804,6 +36803,7 @@
field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
+ field public static final java.lang.String KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL = "drop_video_call_when_answering_audio_call_bool";
field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
@@ -36861,6 +36861,7 @@
field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
field public static final java.lang.String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
field public static final java.lang.String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
+ field public static final java.lang.String KEY_TREAT_DOWNGRADED_VIDEO_CALLS_AS_VIDEO_CALLS_BOOL = "treat_downgraded_video_calls_as_video_calls_bool";
field public static final java.lang.String KEY_USE_HFA_FOR_PROVISIONING_BOOL = "use_hfa_for_provisioning_bool";
field public static final java.lang.String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool";
field public static final java.lang.String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool";
@@ -37466,12 +37467,15 @@
field public static final int NETWORK_TYPE_EVDO_A = 6; // 0x6
field public static final int NETWORK_TYPE_EVDO_B = 12; // 0xc
field public static final int NETWORK_TYPE_GPRS = 1; // 0x1
+ field public static final int NETWORK_TYPE_GSM = 16; // 0x10
field public static final int NETWORK_TYPE_HSDPA = 8; // 0x8
field public static final int NETWORK_TYPE_HSPA = 10; // 0xa
field public static final int NETWORK_TYPE_HSPAP = 15; // 0xf
field public static final int NETWORK_TYPE_HSUPA = 9; // 0x9
field public static final int NETWORK_TYPE_IDEN = 11; // 0xb
+ field public static final int NETWORK_TYPE_IWLAN = 18; // 0x12
field public static final int NETWORK_TYPE_LTE = 13; // 0xd
+ field public static final int NETWORK_TYPE_TD_SCDMA = 17; // 0x11
field public static final int NETWORK_TYPE_UMTS = 3; // 0x3
field public static final int NETWORK_TYPE_UNKNOWN = 0; // 0x0
field public static final int PHONE_TYPE_CDMA = 2; // 0x2
@@ -41000,8 +41004,11 @@
field public static final android.os.Parcelable.Creator<android.view.Display.Mode> CREATOR;
}
- public final class DragAndDropPermissions {
+ public final class DragAndDropPermissions implements android.os.Parcelable {
+ method public int describeContents();
method public void release();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.view.DragAndDropPermissions> CREATOR;
}
public class DragEvent implements android.os.Parcelable {
@@ -41484,10 +41491,6 @@
field public static final int KEYCODE_FOCUS = 80; // 0x50
field public static final int KEYCODE_FORWARD = 125; // 0x7d
field public static final int KEYCODE_FORWARD_DEL = 112; // 0x70
- field public static final int KEYCODE_FP_NAV_DOWN = 281; // 0x119
- field public static final int KEYCODE_FP_NAV_LEFT = 282; // 0x11a
- field public static final int KEYCODE_FP_NAV_RIGHT = 283; // 0x11b
- field public static final int KEYCODE_FP_NAV_UP = 280; // 0x118
field public static final int KEYCODE_FUNCTION = 119; // 0x77
field public static final int KEYCODE_G = 35; // 0x23
field public static final int KEYCODE_GRAVE = 68; // 0x44
@@ -41606,6 +41609,10 @@
field public static final int KEYCODE_SWITCH_CHARSET = 95; // 0x5f
field public static final int KEYCODE_SYM = 63; // 0x3f
field public static final int KEYCODE_SYSRQ = 120; // 0x78
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_DOWN = 281; // 0x119
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_LEFT = 282; // 0x11a
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_RIGHT = 283; // 0x11b
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_UP = 280; // 0x118
field public static final int KEYCODE_T = 48; // 0x30
field public static final int KEYCODE_TAB = 61; // 0x3d
field public static final int KEYCODE_TV = 170; // 0xaa
@@ -44696,6 +44703,7 @@
method public boolean clearMetaKeyStates(int);
method public void closeConnection();
method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
+ method public boolean commitContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public boolean commitText(java.lang.CharSequence, int);
method public boolean deleteSurroundingText(int, int);
@@ -44711,7 +44719,6 @@
method public java.lang.CharSequence getSelectedText(int);
method public java.lang.CharSequence getTextAfterCursor(int, int);
method public java.lang.CharSequence getTextBeforeCursor(int, int);
- method public boolean insertContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
method public boolean performContextMenuAction(int);
method public boolean performEditorAction(int);
method public boolean performPrivateCommand(java.lang.String, android.os.Bundle);
@@ -44866,6 +44873,7 @@
method public abstract boolean clearMetaKeyStates(int);
method public abstract void closeConnection();
method public abstract boolean commitCompletion(android.view.inputmethod.CompletionInfo);
+ method public abstract boolean commitContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public abstract boolean commitText(java.lang.CharSequence, int);
method public abstract boolean deleteSurroundingText(int, int);
@@ -44878,7 +44886,6 @@
method public abstract java.lang.CharSequence getSelectedText(int);
method public abstract java.lang.CharSequence getTextAfterCursor(int, int);
method public abstract java.lang.CharSequence getTextBeforeCursor(int, int);
- method public abstract boolean insertContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
method public abstract boolean performContextMenuAction(int);
method public abstract boolean performEditorAction(int);
method public abstract boolean performPrivateCommand(java.lang.String, android.os.Bundle);
@@ -44900,6 +44907,7 @@
method public boolean clearMetaKeyStates(int);
method public void closeConnection();
method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
+ method public boolean commitContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public boolean commitText(java.lang.CharSequence, int);
method public boolean deleteSurroundingText(int, int);
@@ -44912,7 +44920,6 @@
method public java.lang.CharSequence getSelectedText(int);
method public java.lang.CharSequence getTextAfterCursor(int, int);
method public java.lang.CharSequence getTextBeforeCursor(int, int);
- method public boolean insertContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
method public boolean performContextMenuAction(int);
method public boolean performEditorAction(int);
method public boolean performPrivateCommand(java.lang.String, android.os.Bundle);
@@ -44925,13 +44932,15 @@
method public void setTarget(android.view.inputmethod.InputConnection);
}
- public class InputContentInfo implements android.os.Parcelable {
+ public final class InputContentInfo implements android.os.Parcelable {
ctor public InputContentInfo(android.net.Uri, android.content.ClipDescription);
ctor public InputContentInfo(android.net.Uri, android.content.ClipDescription, android.net.Uri);
method public int describeContents();
method public android.net.Uri getContentUri();
method public android.content.ClipDescription getDescription();
method public android.net.Uri getLinkUri();
+ method public void releasePermission();
+ method public void requestPermission();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.view.inputmethod.InputContentInfo> CREATOR;
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 15e8673..58595b0 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -504,6 +504,7 @@
field public static final int colorPressedHighlight = 16843661; // 0x101038d
field public static final int colorPrimary = 16843827; // 0x1010433
field public static final int colorPrimaryDark = 16843828; // 0x1010434
+ field public static final int colorSecondary = 16844080; // 0x1010530
field public static final int columnCount = 16843639; // 0x1010377
field public static final int columnDelay = 16843215; // 0x10101cf
field public static final int columnOrderPreserved = 16843640; // 0x1010378
@@ -527,9 +528,9 @@
field public static final int contentInsetStart = 16843859; // 0x1010453
field public static final int contentInsetStartWithNavigation = 16844066; // 0x1010522
field public static final int contextClickable = 16844007; // 0x10104e7
- field public static final int contextDescription = 16844082; // 0x1010532
+ field public static final int contextDescription = 16844078; // 0x101052e
field public static final int contextPopupMenuStyle = 16844033; // 0x1010501
- field public static final int contextUri = 16844081; // 0x1010531
+ field public static final int contextUri = 16844077; // 0x101052d
field public static final int controlX1 = 16843772; // 0x10103fc
field public static final int controlX2 = 16843774; // 0x10103fe
field public static final int controlY1 = 16843773; // 0x10103fd
@@ -1148,7 +1149,7 @@
field public static final int rotation = 16843558; // 0x1010326
field public static final int rotationX = 16843559; // 0x1010327
field public static final int rotationY = 16843560; // 0x1010328
- field public static final int roundIcon = 16844080; // 0x1010530
+ field public static final int roundIcon = 16844076; // 0x101052c
field public static final int rowCount = 16843637; // 0x1010375
field public static final int rowDelay = 16843216; // 0x10101d0
field public static final int rowEdgeFlags = 16843329; // 0x1010241
@@ -1220,20 +1221,16 @@
field public static final int shareInterpolator = 16843195; // 0x10101bb
field public static final int sharedUserId = 16842763; // 0x101000b
field public static final int sharedUserLabel = 16843361; // 0x1010261
- field public static final int shortcutCategories = 16844077; // 0x101052d
- field public static final int shortcutDisabledMessage = 16844076; // 0x101052c
- field public static final int shortcutIcon = 16844073; // 0x1010529
+ field public static final int shortcutDisabledMessage = 16844075; // 0x101052b
field public static final int shortcutId = 16844072; // 0x1010528
- field public static final int shortcutIntentAction = 16844078; // 0x101052e
- field public static final int shortcutIntentData = 16844079; // 0x101052f
- field public static final int shortcutLongLabel = 16844075; // 0x101052b
- field public static final int shortcutShortLabel = 16844074; // 0x101052a
+ field public static final int shortcutLongLabel = 16844074; // 0x101052a
+ field public static final int shortcutShortLabel = 16844073; // 0x1010529
field public static final int shouldDisableView = 16843246; // 0x10101ee
field public static final int showAsAction = 16843481; // 0x10102d9
field public static final int showDefault = 16843258; // 0x10101fa
field public static final int showDividers = 16843561; // 0x1010329
field public static final int showForAllUsers = 16844015; // 0x10104ef
- field public static final int showMetadataInPreview = 16844083; // 0x1010533
+ field public static final int showMetadataInPreview = 16844079; // 0x101052f
field public static final deprecated int showOnLockScreen = 16843721; // 0x10103c9
field public static final int showSilent = 16843259; // 0x10101fb
field public static final int showText = 16843949; // 0x10104ad
@@ -9876,8 +9873,6 @@
method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
method public android.graphics.drawable.Drawable getShortcutIconDrawable(android.content.pm.ShortcutInfo, int);
- method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo);
- method public android.os.ParcelFileDescriptor getShortcutIconFd(java.lang.String, java.lang.String, android.os.UserHandle);
method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
method public boolean hasShortcutHostPermission();
method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
@@ -9912,10 +9907,10 @@
method public android.content.pm.LauncherApps.ShortcutQuery setPackage(java.lang.String);
method public android.content.pm.LauncherApps.ShortcutQuery setQueryFlags(int);
method public android.content.pm.LauncherApps.ShortcutQuery setShortcutIds(java.util.List<java.lang.String>);
- field public static final int FLAG_GET_DYNAMIC = 1; // 0x1
field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
- field public static final int FLAG_GET_MANIFEST = 8; // 0x8
- field public static final int FLAG_GET_PINNED = 2; // 0x2
+ field public static final int FLAG_MATCH_DYNAMIC = 1; // 0x1
+ field public static final int FLAG_MATCH_MANIFEST = 8; // 0x8
+ field public static final int FLAG_MATCH_PINNED = 2; // 0x2
}
public class PackageInfo implements android.os.Parcelable {
@@ -10493,7 +10488,6 @@
method public java.lang.CharSequence getDisabledMessage();
method public int getDisabledMessageResourceId();
method public android.os.PersistableBundle getExtras();
- method public int getIconResourceId();
method public java.lang.String getId();
method public android.content.Intent getIntent();
method public long getLastChangedTimestamp();
@@ -10504,14 +10498,11 @@
method public java.lang.CharSequence getShortLabel();
method public int getShortLabelResourceId();
method public android.os.UserHandle getUserHandle();
- method public boolean hasIconFile();
- method public boolean hasIconResource();
method public boolean hasKeyFieldsOnly();
- method public boolean hasStringResourcesResolved();
+ method public boolean isDeclaredInManifest();
method public boolean isDynamic();
method public boolean isEnabled();
method public boolean isImmutable();
- method public boolean isManifestShortcut();
method public boolean isPinned();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR;
@@ -10519,18 +10510,19 @@
}
public static class ShortcutInfo.Builder {
- ctor public ShortcutInfo.Builder(android.content.Context);
+ ctor public deprecated ShortcutInfo.Builder(android.content.Context);
+ ctor public ShortcutInfo.Builder(android.content.Context, java.lang.String);
method public android.content.pm.ShortcutInfo build();
method public android.content.pm.ShortcutInfo.Builder setActivity(android.content.ComponentName);
method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
- method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.String);
+ method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.CharSequence);
method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
- method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
+ method public deprecated android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
- method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.String);
+ method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.CharSequence);
method public android.content.pm.ShortcutInfo.Builder setRank(int);
- method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.String);
+ method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.CharSequence);
}
public class ShortcutManager {
@@ -20066,6 +20058,7 @@
public class InputMethodService extends android.inputmethodservice.AbstractInputMethodService {
ctor public InputMethodService();
method public deprecated boolean enableHardwareAcceleration();
+ method public final boolean exposeContent(android.view.inputmethod.InputContentInfo, android.view.inputmethod.EditorInfo);
method public int getBackDisposition();
method public int getCandidatesHiddenVisibility();
method public android.view.inputmethod.InputBinding getCurrentInputBinding();
@@ -35186,6 +35179,7 @@
field public static final java.lang.String DATA_ROAMING = "data_roaming";
field public static final java.lang.String DEBUG_APP = "debug_app";
field public static final java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
+ field public static final java.lang.String DEVICE_NAME = "device_name";
field public static final java.lang.String DEVICE_PROVISIONED = "device_provisioned";
field public static final java.lang.String HTTP_PROXY = "http_proxy";
field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
@@ -35774,6 +35768,7 @@
field public static final java.lang.String ACTION_NEW_VOICEMAIL = "android.intent.action.NEW_VOICEMAIL";
field public static final java.lang.String ACTION_SYNC_VOICEMAIL = "android.provider.action.SYNC_VOICEMAIL";
field public static final java.lang.String AUTHORITY = "com.android.voicemail";
+ field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.provider.extra.PHONE_ACCOUNT_HANDLE";
field public static final java.lang.String EXTRA_SELF_CHANGE = "com.android.voicemail.extra.SELF_CHANGE";
field public static final java.lang.String PARAM_KEY_SOURCE_PACKAGE = "source_package";
}
@@ -35782,6 +35777,9 @@
method public static android.net.Uri buildSourceUri(java.lang.String);
field public static final java.lang.String CONFIGURATION_STATE = "configuration_state";
field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2
+ field public static final int CONFIGURATION_STATE_CONFIGURING = 3; // 0x3
+ field public static final int CONFIGURATION_STATE_DISABLED = 5; // 0x5
+ field public static final int CONFIGURATION_STATE_FAILED = 4; // 0x4
field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1
field public static final int CONFIGURATION_STATE_OK = 0; // 0x0
field public static final android.net.Uri CONTENT_URI;
@@ -39168,6 +39166,7 @@
field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
field public static final java.lang.String EVENT_CALL_MERGE_FAILED = "android.telecom.event.CALL_MERGE_FAILED";
field public static final java.lang.String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
+ field public static final java.lang.String EXTRA_ANSWERING_DROPS_FG_CALL = "android.telecom.extra.ANSWERING_DROPS_FG_CALL";
field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
field public static final java.lang.String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
@@ -39843,6 +39842,7 @@
field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
+ field public static final java.lang.String KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL = "drop_video_call_when_answering_audio_call_bool";
field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
@@ -39900,6 +39900,7 @@
field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
field public static final java.lang.String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
field public static final java.lang.String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
+ field public static final java.lang.String KEY_TREAT_DOWNGRADED_VIDEO_CALLS_AS_VIDEO_CALLS_BOOL = "treat_downgraded_video_calls_as_video_calls_bool";
field public static final java.lang.String KEY_USE_HFA_FOR_PROVISIONING_BOOL = "use_hfa_for_provisioning_bool";
field public static final java.lang.String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool";
field public static final java.lang.String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool";
@@ -40553,12 +40554,15 @@
field public static final int NETWORK_TYPE_EVDO_A = 6; // 0x6
field public static final int NETWORK_TYPE_EVDO_B = 12; // 0xc
field public static final int NETWORK_TYPE_GPRS = 1; // 0x1
+ field public static final int NETWORK_TYPE_GSM = 16; // 0x10
field public static final int NETWORK_TYPE_HSDPA = 8; // 0x8
field public static final int NETWORK_TYPE_HSPA = 10; // 0xa
field public static final int NETWORK_TYPE_HSPAP = 15; // 0xf
field public static final int NETWORK_TYPE_HSUPA = 9; // 0x9
field public static final int NETWORK_TYPE_IDEN = 11; // 0xb
+ field public static final int NETWORK_TYPE_IWLAN = 18; // 0x12
field public static final int NETWORK_TYPE_LTE = 13; // 0xd
+ field public static final int NETWORK_TYPE_TD_SCDMA = 17; // 0x11
field public static final int NETWORK_TYPE_UMTS = 3; // 0x3
field public static final int NETWORK_TYPE_UNKNOWN = 0; // 0x0
field public static final int PHONE_TYPE_CDMA = 2; // 0x2
@@ -44104,8 +44108,11 @@
field public static final android.os.Parcelable.Creator<android.view.Display.Mode> CREATOR;
}
- public final class DragAndDropPermissions {
+ public final class DragAndDropPermissions implements android.os.Parcelable {
+ method public int describeContents();
method public void release();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.view.DragAndDropPermissions> CREATOR;
}
public class DragEvent implements android.os.Parcelable {
@@ -44588,10 +44595,6 @@
field public static final int KEYCODE_FOCUS = 80; // 0x50
field public static final int KEYCODE_FORWARD = 125; // 0x7d
field public static final int KEYCODE_FORWARD_DEL = 112; // 0x70
- field public static final int KEYCODE_FP_NAV_DOWN = 281; // 0x119
- field public static final int KEYCODE_FP_NAV_LEFT = 282; // 0x11a
- field public static final int KEYCODE_FP_NAV_RIGHT = 283; // 0x11b
- field public static final int KEYCODE_FP_NAV_UP = 280; // 0x118
field public static final int KEYCODE_FUNCTION = 119; // 0x77
field public static final int KEYCODE_G = 35; // 0x23
field public static final int KEYCODE_GRAVE = 68; // 0x44
@@ -44710,6 +44713,10 @@
field public static final int KEYCODE_SWITCH_CHARSET = 95; // 0x5f
field public static final int KEYCODE_SYM = 63; // 0x3f
field public static final int KEYCODE_SYSRQ = 120; // 0x78
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_DOWN = 281; // 0x119
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_LEFT = 282; // 0x11a
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_RIGHT = 283; // 0x11b
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_UP = 280; // 0x118
field public static final int KEYCODE_T = 48; // 0x30
field public static final int KEYCODE_TAB = 61; // 0x3d
field public static final int KEYCODE_TV = 170; // 0xaa
@@ -47803,6 +47810,7 @@
method public boolean clearMetaKeyStates(int);
method public void closeConnection();
method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
+ method public boolean commitContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public boolean commitText(java.lang.CharSequence, int);
method public boolean deleteSurroundingText(int, int);
@@ -47818,7 +47826,6 @@
method public java.lang.CharSequence getSelectedText(int);
method public java.lang.CharSequence getTextAfterCursor(int, int);
method public java.lang.CharSequence getTextBeforeCursor(int, int);
- method public boolean insertContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
method public boolean performContextMenuAction(int);
method public boolean performEditorAction(int);
method public boolean performPrivateCommand(java.lang.String, android.os.Bundle);
@@ -47973,6 +47980,7 @@
method public abstract boolean clearMetaKeyStates(int);
method public abstract void closeConnection();
method public abstract boolean commitCompletion(android.view.inputmethod.CompletionInfo);
+ method public abstract boolean commitContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public abstract boolean commitText(java.lang.CharSequence, int);
method public abstract boolean deleteSurroundingText(int, int);
@@ -47985,7 +47993,6 @@
method public abstract java.lang.CharSequence getSelectedText(int);
method public abstract java.lang.CharSequence getTextAfterCursor(int, int);
method public abstract java.lang.CharSequence getTextBeforeCursor(int, int);
- method public abstract boolean insertContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
method public abstract boolean performContextMenuAction(int);
method public abstract boolean performEditorAction(int);
method public abstract boolean performPrivateCommand(java.lang.String, android.os.Bundle);
@@ -48007,6 +48014,7 @@
method public boolean clearMetaKeyStates(int);
method public void closeConnection();
method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
+ method public boolean commitContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public boolean commitText(java.lang.CharSequence, int);
method public boolean deleteSurroundingText(int, int);
@@ -48019,7 +48027,6 @@
method public java.lang.CharSequence getSelectedText(int);
method public java.lang.CharSequence getTextAfterCursor(int, int);
method public java.lang.CharSequence getTextBeforeCursor(int, int);
- method public boolean insertContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
method public boolean performContextMenuAction(int);
method public boolean performEditorAction(int);
method public boolean performPrivateCommand(java.lang.String, android.os.Bundle);
@@ -48032,13 +48039,15 @@
method public void setTarget(android.view.inputmethod.InputConnection);
}
- public class InputContentInfo implements android.os.Parcelable {
+ public final class InputContentInfo implements android.os.Parcelable {
ctor public InputContentInfo(android.net.Uri, android.content.ClipDescription);
ctor public InputContentInfo(android.net.Uri, android.content.ClipDescription, android.net.Uri);
method public int describeContents();
method public android.net.Uri getContentUri();
method public android.content.ClipDescription getDescription();
method public android.net.Uri getLinkUri();
+ method public void releasePermission();
+ method public void requestPermission();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.view.inputmethod.InputContentInfo> CREATOR;
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 4bb7a79..af04012 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -397,6 +397,7 @@
field public static final int colorPressedHighlight = 16843661; // 0x101038d
field public static final int colorPrimary = 16843827; // 0x1010433
field public static final int colorPrimaryDark = 16843828; // 0x1010434
+ field public static final int colorSecondary = 16844080; // 0x1010530
field public static final int columnCount = 16843639; // 0x1010377
field public static final int columnDelay = 16843215; // 0x10101cf
field public static final int columnOrderPreserved = 16843640; // 0x1010378
@@ -420,9 +421,9 @@
field public static final int contentInsetStart = 16843859; // 0x1010453
field public static final int contentInsetStartWithNavigation = 16844066; // 0x1010522
field public static final int contextClickable = 16844007; // 0x10104e7
- field public static final int contextDescription = 16844082; // 0x1010532
+ field public static final int contextDescription = 16844078; // 0x101052e
field public static final int contextPopupMenuStyle = 16844033; // 0x1010501
- field public static final int contextUri = 16844081; // 0x1010531
+ field public static final int contextUri = 16844077; // 0x101052d
field public static final int controlX1 = 16843772; // 0x10103fc
field public static final int controlX2 = 16843774; // 0x10103fe
field public static final int controlY1 = 16843773; // 0x10103fd
@@ -1041,7 +1042,7 @@
field public static final int rotation = 16843558; // 0x1010326
field public static final int rotationX = 16843559; // 0x1010327
field public static final int rotationY = 16843560; // 0x1010328
- field public static final int roundIcon = 16844080; // 0x1010530
+ field public static final int roundIcon = 16844076; // 0x101052c
field public static final int rowCount = 16843637; // 0x1010375
field public static final int rowDelay = 16843216; // 0x10101d0
field public static final int rowEdgeFlags = 16843329; // 0x1010241
@@ -1109,20 +1110,16 @@
field public static final int shareInterpolator = 16843195; // 0x10101bb
field public static final int sharedUserId = 16842763; // 0x101000b
field public static final int sharedUserLabel = 16843361; // 0x1010261
- field public static final int shortcutCategories = 16844077; // 0x101052d
- field public static final int shortcutDisabledMessage = 16844076; // 0x101052c
- field public static final int shortcutIcon = 16844073; // 0x1010529
+ field public static final int shortcutDisabledMessage = 16844075; // 0x101052b
field public static final int shortcutId = 16844072; // 0x1010528
- field public static final int shortcutIntentAction = 16844078; // 0x101052e
- field public static final int shortcutIntentData = 16844079; // 0x101052f
- field public static final int shortcutLongLabel = 16844075; // 0x101052b
- field public static final int shortcutShortLabel = 16844074; // 0x101052a
+ field public static final int shortcutLongLabel = 16844074; // 0x101052a
+ field public static final int shortcutShortLabel = 16844073; // 0x1010529
field public static final int shouldDisableView = 16843246; // 0x10101ee
field public static final int showAsAction = 16843481; // 0x10102d9
field public static final int showDefault = 16843258; // 0x10101fa
field public static final int showDividers = 16843561; // 0x1010329
field public static final int showForAllUsers = 16844015; // 0x10104ef
- field public static final int showMetadataInPreview = 16844083; // 0x1010533
+ field public static final int showMetadataInPreview = 16844079; // 0x101052f
field public static final deprecated int showOnLockScreen = 16843721; // 0x10103c9
field public static final int showSilent = 16843259; // 0x10101fb
field public static final int showText = 16843949; // 0x10104ad
@@ -9534,8 +9531,6 @@
method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
method public android.graphics.drawable.Drawable getShortcutIconDrawable(android.content.pm.ShortcutInfo, int);
- method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo);
- method public android.os.ParcelFileDescriptor getShortcutIconFd(java.lang.String, java.lang.String, android.os.UserHandle);
method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
method public boolean hasShortcutHostPermission();
method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
@@ -9570,10 +9565,10 @@
method public android.content.pm.LauncherApps.ShortcutQuery setPackage(java.lang.String);
method public android.content.pm.LauncherApps.ShortcutQuery setQueryFlags(int);
method public android.content.pm.LauncherApps.ShortcutQuery setShortcutIds(java.util.List<java.lang.String>);
- field public static final int FLAG_GET_DYNAMIC = 1; // 0x1
field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
- field public static final int FLAG_GET_MANIFEST = 8; // 0x8
- field public static final int FLAG_GET_PINNED = 2; // 0x2
+ field public static final int FLAG_MATCH_DYNAMIC = 1; // 0x1
+ field public static final int FLAG_MATCH_MANIFEST = 8; // 0x8
+ field public static final int FLAG_MATCH_PINNED = 2; // 0x2
}
public class PackageInfo implements android.os.Parcelable {
@@ -10082,7 +10077,6 @@
method public java.lang.CharSequence getDisabledMessage();
method public int getDisabledMessageResourceId();
method public android.os.PersistableBundle getExtras();
- method public int getIconResourceId();
method public java.lang.String getId();
method public android.content.Intent getIntent();
method public long getLastChangedTimestamp();
@@ -10093,14 +10087,11 @@
method public java.lang.CharSequence getShortLabel();
method public int getShortLabelResourceId();
method public android.os.UserHandle getUserHandle();
- method public boolean hasIconFile();
- method public boolean hasIconResource();
method public boolean hasKeyFieldsOnly();
- method public boolean hasStringResourcesResolved();
+ method public boolean isDeclaredInManifest();
method public boolean isDynamic();
method public boolean isEnabled();
method public boolean isImmutable();
- method public boolean isManifestShortcut();
method public boolean isPinned();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR;
@@ -10108,18 +10099,19 @@
}
public static class ShortcutInfo.Builder {
- ctor public ShortcutInfo.Builder(android.content.Context);
+ ctor public deprecated ShortcutInfo.Builder(android.content.Context);
+ ctor public ShortcutInfo.Builder(android.content.Context, java.lang.String);
method public android.content.pm.ShortcutInfo build();
method public android.content.pm.ShortcutInfo.Builder setActivity(android.content.ComponentName);
method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
- method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.String);
+ method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.CharSequence);
method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
- method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
+ method public deprecated android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
- method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.String);
+ method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.CharSequence);
method public android.content.pm.ShortcutInfo.Builder setRank(int);
- method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.String);
+ method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.CharSequence);
}
public class ShortcutManager {
@@ -18880,6 +18872,7 @@
public class InputMethodService extends android.inputmethodservice.AbstractInputMethodService {
ctor public InputMethodService();
method public deprecated boolean enableHardwareAcceleration();
+ method public final boolean exposeContent(android.view.inputmethod.InputContentInfo, android.view.inputmethod.EditorInfo);
method public int getBackDisposition();
method public int getCandidatesHiddenVisibility();
method public android.view.inputmethod.InputBinding getCurrentInputBinding();
@@ -32555,6 +32548,7 @@
field public static final java.lang.String DATA_ROAMING = "data_roaming";
field public static final java.lang.String DEBUG_APP = "debug_app";
field public static final java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
+ field public static final java.lang.String DEVICE_NAME = "device_name";
field public static final java.lang.String DEVICE_PROVISIONED = "device_provisioned";
field public static final java.lang.String HTTP_PROXY = "http_proxy";
field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
@@ -33143,6 +33137,7 @@
field public static final java.lang.String ACTION_NEW_VOICEMAIL = "android.intent.action.NEW_VOICEMAIL";
field public static final java.lang.String ACTION_SYNC_VOICEMAIL = "android.provider.action.SYNC_VOICEMAIL";
field public static final java.lang.String AUTHORITY = "com.android.voicemail";
+ field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.provider.extra.PHONE_ACCOUNT_HANDLE";
field public static final java.lang.String EXTRA_SELF_CHANGE = "com.android.voicemail.extra.SELF_CHANGE";
field public static final java.lang.String PARAM_KEY_SOURCE_PACKAGE = "source_package";
}
@@ -33151,6 +33146,9 @@
method public static android.net.Uri buildSourceUri(java.lang.String);
field public static final java.lang.String CONFIGURATION_STATE = "configuration_state";
field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2
+ field public static final int CONFIGURATION_STATE_CONFIGURING = 3; // 0x3
+ field public static final int CONFIGURATION_STATE_DISABLED = 5; // 0x5
+ field public static final int CONFIGURATION_STATE_FAILED = 4; // 0x4
field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1
field public static final int CONFIGURATION_STATE_OK = 0; // 0x0
field public static final android.net.Uri CONTENT_URI;
@@ -36397,6 +36395,7 @@
field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
field public static final java.lang.String EVENT_CALL_MERGE_FAILED = "android.telecom.event.CALL_MERGE_FAILED";
field public static final java.lang.String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
+ field public static final java.lang.String EXTRA_ANSWERING_DROPS_FG_CALL = "android.telecom.extra.ANSWERING_DROPS_FG_CALL";
field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
field public static final java.lang.String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
@@ -36882,6 +36881,7 @@
field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
+ field public static final java.lang.String KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL = "drop_video_call_when_answering_audio_call_bool";
field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
@@ -36939,6 +36939,7 @@
field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
field public static final java.lang.String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
field public static final java.lang.String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
+ field public static final java.lang.String KEY_TREAT_DOWNGRADED_VIDEO_CALLS_AS_VIDEO_CALLS_BOOL = "treat_downgraded_video_calls_as_video_calls_bool";
field public static final java.lang.String KEY_USE_HFA_FOR_PROVISIONING_BOOL = "use_hfa_for_provisioning_bool";
field public static final java.lang.String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool";
field public static final java.lang.String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool";
@@ -37544,12 +37545,15 @@
field public static final int NETWORK_TYPE_EVDO_A = 6; // 0x6
field public static final int NETWORK_TYPE_EVDO_B = 12; // 0xc
field public static final int NETWORK_TYPE_GPRS = 1; // 0x1
+ field public static final int NETWORK_TYPE_GSM = 16; // 0x10
field public static final int NETWORK_TYPE_HSDPA = 8; // 0x8
field public static final int NETWORK_TYPE_HSPA = 10; // 0xa
field public static final int NETWORK_TYPE_HSPAP = 15; // 0xf
field public static final int NETWORK_TYPE_HSUPA = 9; // 0x9
field public static final int NETWORK_TYPE_IDEN = 11; // 0xb
+ field public static final int NETWORK_TYPE_IWLAN = 18; // 0x12
field public static final int NETWORK_TYPE_LTE = 13; // 0xd
+ field public static final int NETWORK_TYPE_TD_SCDMA = 17; // 0x11
field public static final int NETWORK_TYPE_UMTS = 3; // 0x3
field public static final int NETWORK_TYPE_UNKNOWN = 0; // 0x0
field public static final int PHONE_TYPE_CDMA = 2; // 0x2
@@ -41080,8 +41084,11 @@
field public static final android.os.Parcelable.Creator<android.view.Display.Mode> CREATOR;
}
- public final class DragAndDropPermissions {
+ public final class DragAndDropPermissions implements android.os.Parcelable {
+ method public int describeContents();
method public void release();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.view.DragAndDropPermissions> CREATOR;
}
public class DragEvent implements android.os.Parcelable {
@@ -41564,10 +41571,6 @@
field public static final int KEYCODE_FOCUS = 80; // 0x50
field public static final int KEYCODE_FORWARD = 125; // 0x7d
field public static final int KEYCODE_FORWARD_DEL = 112; // 0x70
- field public static final int KEYCODE_FP_NAV_DOWN = 281; // 0x119
- field public static final int KEYCODE_FP_NAV_LEFT = 282; // 0x11a
- field public static final int KEYCODE_FP_NAV_RIGHT = 283; // 0x11b
- field public static final int KEYCODE_FP_NAV_UP = 280; // 0x118
field public static final int KEYCODE_FUNCTION = 119; // 0x77
field public static final int KEYCODE_G = 35; // 0x23
field public static final int KEYCODE_GRAVE = 68; // 0x44
@@ -41686,6 +41689,10 @@
field public static final int KEYCODE_SWITCH_CHARSET = 95; // 0x5f
field public static final int KEYCODE_SYM = 63; // 0x3f
field public static final int KEYCODE_SYSRQ = 120; // 0x78
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_DOWN = 281; // 0x119
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_LEFT = 282; // 0x11a
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_RIGHT = 283; // 0x11b
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_UP = 280; // 0x118
field public static final int KEYCODE_T = 48; // 0x30
field public static final int KEYCODE_TAB = 61; // 0x3d
field public static final int KEYCODE_TV = 170; // 0xaa
@@ -44776,6 +44783,7 @@
method public boolean clearMetaKeyStates(int);
method public void closeConnection();
method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
+ method public boolean commitContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public boolean commitText(java.lang.CharSequence, int);
method public boolean deleteSurroundingText(int, int);
@@ -44791,7 +44799,6 @@
method public java.lang.CharSequence getSelectedText(int);
method public java.lang.CharSequence getTextAfterCursor(int, int);
method public java.lang.CharSequence getTextBeforeCursor(int, int);
- method public boolean insertContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
method public boolean performContextMenuAction(int);
method public boolean performEditorAction(int);
method public boolean performPrivateCommand(java.lang.String, android.os.Bundle);
@@ -44946,6 +44953,7 @@
method public abstract boolean clearMetaKeyStates(int);
method public abstract void closeConnection();
method public abstract boolean commitCompletion(android.view.inputmethod.CompletionInfo);
+ method public abstract boolean commitContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public abstract boolean commitText(java.lang.CharSequence, int);
method public abstract boolean deleteSurroundingText(int, int);
@@ -44958,7 +44966,6 @@
method public abstract java.lang.CharSequence getSelectedText(int);
method public abstract java.lang.CharSequence getTextAfterCursor(int, int);
method public abstract java.lang.CharSequence getTextBeforeCursor(int, int);
- method public abstract boolean insertContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
method public abstract boolean performContextMenuAction(int);
method public abstract boolean performEditorAction(int);
method public abstract boolean performPrivateCommand(java.lang.String, android.os.Bundle);
@@ -44980,6 +44987,7 @@
method public boolean clearMetaKeyStates(int);
method public void closeConnection();
method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
+ method public boolean commitContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public boolean commitText(java.lang.CharSequence, int);
method public boolean deleteSurroundingText(int, int);
@@ -44992,7 +45000,6 @@
method public java.lang.CharSequence getSelectedText(int);
method public java.lang.CharSequence getTextAfterCursor(int, int);
method public java.lang.CharSequence getTextBeforeCursor(int, int);
- method public boolean insertContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
method public boolean performContextMenuAction(int);
method public boolean performEditorAction(int);
method public boolean performPrivateCommand(java.lang.String, android.os.Bundle);
@@ -45005,13 +45012,15 @@
method public void setTarget(android.view.inputmethod.InputConnection);
}
- public class InputContentInfo implements android.os.Parcelable {
+ public final class InputContentInfo implements android.os.Parcelable {
ctor public InputContentInfo(android.net.Uri, android.content.ClipDescription);
ctor public InputContentInfo(android.net.Uri, android.content.ClipDescription, android.net.Uri);
method public int describeContents();
method public android.net.Uri getContentUri();
method public android.content.ClipDescription getDescription();
method public android.net.Uri getLinkUri();
+ method public void releasePermission();
+ method public void requestPermission();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.view.inputmethod.InputContentInfo> CREATOR;
}
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 69b5a17..5bf8076 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -122,6 +122,11 @@
return;
}
+ if ("whitelist".equals(op)) {
+ doPrintWhitelist();
+ return;
+ }
+
System.err.println("Unknown command");
showUsage();
}
@@ -604,6 +609,20 @@
}
}
+ private void doPrintWhitelist() {
+ try {
+ final String[] whitelist = mBmgr.getTransportWhitelist();
+ if (whitelist != null) {
+ for (String transport : whitelist) {
+ System.out.println(transport);
+ }
+ }
+ } catch (RemoteException e) {
+ System.err.println(e.toString());
+ System.err.println(BMGR_NOT_RUNNING_ERR);
+ }
+ }
+
private String nextArg() {
if (mNextArg >= mArgs.length) {
return null;
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 4470eda..c6834f9 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -254,6 +254,10 @@
return runMovePrimaryStorage();
}
+ if ("set-user-restriction".equals(op)) {
+ return runSetUserRestriction();
+ }
+
try {
if (args.length == 1) {
if (args[0].equalsIgnoreCase("-l")) {
@@ -1054,6 +1058,38 @@
}
}
+ public int runSetUserRestriction() {
+ int userId = UserHandle.USER_SYSTEM;
+ String opt = nextOption();
+ if (opt != null && "--user".equals(opt)) {
+ String arg = nextArg();
+ if (arg == null || !isNumber(arg)) {
+ System.err.println("Error: valid userId not specified");
+ return 1;
+ }
+ userId = Integer.parseInt(arg);
+ }
+
+ String restriction = nextArg();
+ String arg = nextArg();
+ boolean value;
+ if ("1".equals(arg)) {
+ value = true;
+ } else if ("0".equals(arg)) {
+ value = false;
+ } else {
+ System.err.println("Error: valid value not specified");
+ return 1;
+ }
+ try {
+ mUm.setUserRestriction(restriction, value, userId);
+ return 0;
+ } catch (RemoteException e) {
+ System.err.println(e.toString());
+ return 1;
+ }
+ }
+
static class ClearDataObserver extends IPackageDataObserver.Stub {
boolean finished;
boolean result;
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 7841d29..053ba7d 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -1064,15 +1064,15 @@
/**
* @hide
* TODO: For animatorSet defined in XML, we can use a flag to indicate what the play order
- * if defined (i.e. sequential or together), then we can use the flag instead of calculate
- * dynamically.
+ * if defined (i.e. sequential or together), then we can use the flag instead of calculating
+ * dynamically. Note that when AnimatorSet is empty this method returns true.
* @return whether all the animators in the set are supposed to play together
*/
public boolean shouldPlayTogether() {
updateAnimatorsDuration();
createDependencyGraph();
// All the child nodes are set out to play right after the delay animation
- return mRootNode.mChildNodes.size() == mNodes.size() - 1;
+ return mRootNode.mChildNodes == null || mRootNode.mChildNodes.size() == mNodes.size() - 1;
}
@Override
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index ec8b288..06a01fc 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -306,7 +306,7 @@
* </thead>
*
* <tbody>
- * <tr><th colspan="3" align="left" border="0">{@link android.app.Activity#onCreate onCreate()}</th>
+ * <tr><td colspan="3" align="left" border="0">{@link android.app.Activity#onCreate onCreate()}</td>
* <td>Called when the activity is first created.
* This is where you should do all of your normal static set up:
* create views, bind data to lists, etc. This method also
@@ -318,7 +318,7 @@
* </tr>
*
* <tr><td rowspan="5" style="border-left: none; border-right: none;"> </td>
- * <th colspan="2" align="left" border="0">{@link android.app.Activity#onRestart onRestart()}</th>
+ * <td colspan="2" align="left" border="0">{@link android.app.Activity#onRestart onRestart()}</td>
* <td>Called after your activity has been stopped, prior to it being
* started again.
* <p>Always followed by <code>onStart()</code></td>
@@ -326,7 +326,7 @@
* <td align="center"><code>onStart()</code></td>
* </tr>
*
- * <tr><th colspan="2" align="left" border="0">{@link android.app.Activity#onStart onStart()}</th>
+ * <tr><td colspan="2" align="left" border="0">{@link android.app.Activity#onStart onStart()}</td>
* <td>Called when the activity is becoming visible to the user.
* <p>Followed by <code>onResume()</code> if the activity comes
* to the foreground, or <code>onStop()</code> if it becomes hidden.</td>
@@ -335,7 +335,7 @@
* </tr>
*
* <tr><td rowspan="2" style="border-left: none;"> </td>
- * <th align="left" border="0">{@link android.app.Activity#onResume onResume()}</th>
+ * <td align="left" border="0">{@link android.app.Activity#onResume onResume()}</td>
* <td>Called when the activity will start
* interacting with the user. At this point your activity is at
* the top of the activity stack, with user input going to it.
@@ -344,7 +344,7 @@
* <td align="center"><code>onPause()</code></td>
* </tr>
*
- * <tr><th align="left" border="0">{@link android.app.Activity#onPause onPause()}</th>
+ * <tr><td align="left" border="0">{@link android.app.Activity#onPause onPause()}</td>
* <td>Called when the system is about to start resuming a previous
* activity. This is typically used to commit unsaved changes to
* persistent data, stop animations and other things that may be consuming
@@ -358,7 +358,7 @@
* <code>onStop()</code></td>
* </tr>
*
- * <tr><th colspan="2" align="left" border="0">{@link android.app.Activity#onStop onStop()}</th>
+ * <tr><td colspan="2" align="left" border="0">{@link android.app.Activity#onStop onStop()}</td>
* <td>Called when the activity is no longer visible to the user, because
* another activity has been resumed and is covering this one. This
* may happen either because a new activity is being started, an existing
@@ -372,7 +372,7 @@
* <code>onDestroy()</code></td>
* </tr>
*
- * <tr><th colspan="3" align="left" border="0">{@link android.app.Activity#onDestroy onDestroy()}</th>
+ * <tr><td colspan="3" align="left" border="0">{@link android.app.Activity#onDestroy onDestroy()}</td>
* <td>The final call you receive before your
* activity is destroyed. This can happen either because the
* activity is finishing (someone called {@link Activity#finish} on
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 3a70a4c..33ae553 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.IIntentSender;
+import android.content.res.Configuration;
import android.os.IBinder;
import android.service.voice.IVoiceInteractionSession;
@@ -151,4 +152,13 @@
* such as Power Save mode.
*/
public abstract void setPendingIntentWhitelistDuration(IIntentSender target, long duration);
+
+ /**
+ * Updates and persists the {@link Configuration} for a given user.
+ *
+ * @param values the configuration to update
+ * @param userId the user to update the configuration for
+ */
+ public abstract void updatePersistentConfigurationForUser(@NonNull Configuration values,
+ int userId);
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index f12c284..cee5646 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1779,9 +1779,10 @@
case START_BACKUP_AGENT_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
- ApplicationInfo info = ApplicationInfo.CREATOR.createFromParcel(data);
+ String packageName = data.readString();
int backupRestoreMode = data.readInt();
- boolean success = bindBackupAgent(info, backupRestoreMode);
+ int userId = data.readInt();
+ boolean success = bindBackupAgent(packageName, backupRestoreMode, userId);
reply.writeNoException();
reply.writeInt(success ? 1 : 0);
return true;
@@ -1812,12 +1813,13 @@
return true;
}
- case KILL_APPLICATION_WITH_APPID_TRANSACTION: {
+ case KILL_APPLICATION_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
String pkg = data.readString();
- int appid = data.readInt();
+ int appId = data.readInt();
+ int userId = data.readInt();
String reason = data.readString();
- killApplicationWithAppId(pkg, appid, reason);
+ killApplication(pkg, appId, userId, reason);
reply.writeNoException();
return true;
}
@@ -2369,7 +2371,8 @@
data.enforceInterface(IActivityManager.descriptor);
IUserSwitchObserver observer = IUserSwitchObserver.Stub.asInterface(
data.readStrongBinder());
- registerUserSwitchObserver(observer);
+ String name = data.readString();
+ registerUserSwitchObserver(observer, name);
reply.writeNoException();
return true;
}
@@ -4448,13 +4451,14 @@
return binder;
}
- public boolean bindBackupAgent(ApplicationInfo app, int backupRestoreMode)
+ public boolean bindBackupAgent(String packageName, int backupRestoreMode, int userId)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
- app.writeToParcel(data, 0);
+ data.writeString(packageName);
data.writeInt(backupRestoreMode);
+ data.writeInt(userId);
mRemote.transact(START_BACKUP_AGENT_TRANSACTION, data, reply, 0);
reply.readException();
boolean success = reply.readInt() != 0;
@@ -5289,15 +5293,16 @@
reply.recycle();
}
- public void killApplicationWithAppId(String pkg, int appid, String reason)
+ public void killApplication(String pkg, int appId, int userId, String reason)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeString(pkg);
- data.writeInt(appid);
+ data.writeInt(appId);
+ data.writeInt(userId);
data.writeString(reason);
- mRemote.transact(KILL_APPLICATION_WITH_APPID_TRANSACTION, data, reply, 0);
+ mRemote.transact(KILL_APPLICATION_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
@@ -6056,11 +6061,13 @@
return result;
}
- public void registerUserSwitchObserver(IUserSwitchObserver observer) throws RemoteException {
+ public void registerUserSwitchObserver(IUserSwitchObserver observer,
+ String name) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(observer != null ? observer.asBinder() : null);
+ data.writeString(name);
mRemote.transact(REGISTER_USER_SWITCH_OBSERVER_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 0728bdf..3f15a75 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -236,6 +236,7 @@
boolean mSystemThread = false;
boolean mJitEnabled = false;
boolean mSomeActivitiesChanged = false;
+ boolean mUpdatingSystemConfig = false;
// These can be accessed by multiple threads; mPackages is the lock.
// XXX For now we keep around information about all packages we have
@@ -1574,7 +1575,9 @@
case CONFIGURATION_CHANGED:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "configChanged");
mCurDefaultDisplayDpi = ((Configuration)msg.obj).densityDpi;
+ mUpdatingSystemConfig = true;
handleConfigurationChanged((Configuration)msg.obj, null);
+ mUpdatingSystemConfig = false;
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case CLEAN_UP_CONTEXT:
@@ -4629,7 +4632,14 @@
// onConfigurationChanged
int diff = activity.mCurrentConfig.diff(newConfig);
if (diff != 0) {
- shouldChangeConfig = true;
+ // Always send the task-level config changes. For system-level configuration, if
+ // this activity doesn't handle any of the config changes, then don't bother
+ // calling onConfigurationChanged as we're going to destroy it.
+ if (!mUpdatingSystemConfig
+ || (~activity.mActivityInfo.getRealConfigChanged() & diff) == 0
+ || !reportToActivity) {
+ shouldChangeConfig = true;
+ }
}
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index cf663a3..e6ca520 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -16,6 +16,8 @@
package android.app;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentProvider;
@@ -30,6 +32,7 @@
import android.content.ReceiverCallNotAllowedException;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
@@ -155,10 +158,9 @@
private final String mBasePackageName;
private final String mOpPackageName;
- private final ResourcesManager mResourcesManager;
- private final Resources mResources;
- private final Display mDisplay; // may be null if default display
- private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments();
+ private final @NonNull ResourcesManager mResourcesManager;
+ private final @NonNull Resources mResources;
+ private @Nullable Display mDisplay; // may be null if default display
private final int mFlags;
@@ -1897,18 +1899,6 @@
mUser, mFlags, display, null, Display.INVALID_DISPLAY);
}
- Display getDisplay() {
- if (mDisplay != null) {
- return mDisplay;
- }
- return ResourcesManager.getInstance().getAdjustedDisplay(
- Display.DEFAULT_DISPLAY, mDisplayAdjustments);
- }
-
- private int getDisplayId() {
- return mDisplay != null ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
- }
-
@Override
public Context createDeviceProtectedStorageContext() {
final int flags = (mFlags & ~Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE)
@@ -1941,8 +1931,23 @@
}
@Override
+ public Display getDisplay() {
+ final DisplayAdjustments displayAdjustments = mResources.getDisplayAdjustments();
+ if (mDisplay == null) {
+ return mResourcesManager.getAdjustedDisplay(Display.DEFAULT_DISPLAY,
+ displayAdjustments);
+ }
+
+ if (!mDisplay.getDisplayAdjustments().equals(displayAdjustments)) {
+ mDisplay = mResourcesManager.getAdjustedDisplay(mDisplay.getDisplayId(),
+ displayAdjustments);
+ }
+ return mDisplay;
+ }
+
+ @Override
public DisplayAdjustments getDisplayAdjustments(int displayId) {
- return mDisplayAdjustments;
+ return mResources.getDisplayAdjustments();
}
@Override
@@ -2057,11 +2062,6 @@
? packageInfo.getCompatibilityInfo()
: CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
}
- mDisplayAdjustments.setCompatibilityInfo(compatInfo);
- mDisplayAdjustments.setConfiguration(overrideConfiguration);
-
- mDisplay = (createDisplayWithId == Display.INVALID_DISPLAY) ? display
- : ResourcesManager.getInstance().getAdjustedDisplay(displayId, mDisplayAdjustments);
Resources resources = packageInfo.getResources(mainThread);
if (resources != null) {
@@ -2101,6 +2101,9 @@
}
mResources = resources;
+ mDisplay = (createDisplayWithId == Display.INVALID_DISPLAY) ? display
+ : mResourcesManager.getAdjustedDisplay(displayId, mResources.getDisplayAdjustments());
+
if (container != null) {
mBasePackageName = container.mBasePackageName;
mOpPackageName = container.mOpPackageName;
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 81788da..3f7ff0b 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -250,7 +250,7 @@
public IBinder peekService(Intent service, String resolvedType, String callingPackage)
throws RemoteException;
- public boolean bindBackupAgent(ApplicationInfo appInfo, int backupRestoreMode)
+ public boolean bindBackupAgent(String packageName, int backupRestoreMode, int userId)
throws RemoteException;
public void clearPendingBackup() throws RemoteException;
public void backupAgentCreated(String packageName, IBinder agent) throws RemoteException;
@@ -398,7 +398,7 @@
public void addPackageDependency(String packageName) throws RemoteException;
- public void killApplicationWithAppId(String pkg, int appid, String reason)
+ public void killApplication(String pkg, int appId, int userId, String reason)
throws RemoteException;
public void closeSystemDialogs(String reason) throws RemoteException;
@@ -512,7 +512,8 @@
public int getLaunchedFromUid(IBinder activityToken) throws RemoteException;
public String getLaunchedFromPackage(IBinder activityToken) throws RemoteException;
- public void registerUserSwitchObserver(IUserSwitchObserver observer) throws RemoteException;
+ public void registerUserSwitchObserver(IUserSwitchObserver observer,
+ String name) throws RemoteException;
public void unregisterUserSwitchObserver(IUserSwitchObserver observer) throws RemoteException;
public void requestBugReport(int bugreportType) throws RemoteException;
@@ -852,7 +853,7 @@
int GET_UID_FOR_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+92;
int HANDLE_INCOMING_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+93;
int ADD_PACKAGE_DEPENDENCY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+94;
- int KILL_APPLICATION_WITH_APPID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+95;
+ int KILL_APPLICATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+95;
int CLOSE_SYSTEM_DIALOGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+96;
int GET_PROCESS_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+97;
int KILL_APPLICATION_PROCESS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+98;
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 0b62ed2..b889c8f 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1072,6 +1072,7 @@
final class Args extends BroadcastReceiver.PendingResult implements Runnable {
private Intent mCurIntent;
private final boolean mOrdered;
+ private boolean mDispatched;
public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
boolean ordered, boolean sticky, int sendingUser) {
@@ -1096,9 +1097,13 @@
final IActivityManager mgr = ActivityManagerNative.getDefault();
final Intent intent = mCurIntent;
+ if (intent == null) {
+ Log.wtf(TAG, "Null intent being dispatched, mDispatched=" + mDispatched);
+ }
+
mCurIntent = null;
-
- if (receiver == null || mForgotten) {
+ mDispatched = true;
+ if (receiver == null || intent == null || mForgotten) {
if (mRegistered && ordered) {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing null broadcast to " + mReceiver);
diff --git a/core/java/android/app/Presentation.java b/core/java/android/app/Presentation.java
index e110dcb..70007f5 100644
--- a/core/java/android/app/Presentation.java
+++ b/core/java/android/app/Presentation.java
@@ -310,7 +310,7 @@
final WindowManagerImpl outerWindowManager =
(WindowManagerImpl)outerContext.getSystemService(Context.WINDOW_SERVICE);
final WindowManagerImpl displayWindowManager =
- outerWindowManager.createPresentationWindowManager(display);
+ outerWindowManager.createPresentationWindowManager(displayContext);
return new ContextThemeWrapper(displayContext, theme) {
@Override
public Object getSystemService(String name) {
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index f56a6ad..c4673a3 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -149,17 +149,17 @@
}
DisplayMetrics getDisplayMetrics() {
- return getDisplayMetrics(Display.DEFAULT_DISPLAY);
+ return getDisplayMetrics(Display.DEFAULT_DISPLAY,
+ DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
}
/**
* Protected so that tests can override and returns something a fixed value.
*/
@VisibleForTesting
- protected @NonNull DisplayMetrics getDisplayMetrics(int displayId) {
+ protected @NonNull DisplayMetrics getDisplayMetrics(int displayId, DisplayAdjustments da) {
DisplayMetrics dm = new DisplayMetrics();
- final Display display =
- getAdjustedDisplay(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
+ final Display display = getAdjustedDisplay(displayId, da);
if (display != null) {
display.getMetrics(dm);
} else {
@@ -304,10 +304,13 @@
}
private @NonNull ResourcesImpl createResourcesImpl(@NonNull ResourcesKey key) {
- AssetManager assets = createAssetManager(key);
- DisplayMetrics dm = getDisplayMetrics(key.mDisplayId);
- Configuration config = generateConfig(key, dm);
- ResourcesImpl impl = new ResourcesImpl(assets, dm, config, key.mCompatInfo);
+ final DisplayAdjustments daj = new DisplayAdjustments(key.mOverrideConfiguration);
+ daj.setCompatibilityInfo(key.mCompatInfo);
+
+ final AssetManager assets = createAssetManager(key);
+ final DisplayMetrics dm = getDisplayMetrics(key.mDisplayId, daj);
+ final Configuration config = generateConfig(key, dm);
+ final ResourcesImpl impl = new ResourcesImpl(assets, dm, config, daj);
if (DEBUG) {
Slog.d(TAG, "- creating impl=" + impl + " with key: " + key);
}
@@ -804,7 +807,16 @@
}
tmpConfig.setTo(config);
if (!isDefaultDisplay) {
- dm = getDisplayMetrics(displayId);
+ // Get new DisplayMetrics based on the DisplayAdjustments given
+ // to the ResourcesImpl. Udate a copy if the CompatibilityInfo
+ // changed, because the ResourcesImpl object will handle the
+ // update internally.
+ DisplayAdjustments daj = r.getDisplayAdjustments();
+ if (compat != null) {
+ daj = new DisplayAdjustments(daj);
+ daj.setCompatibilityInfo(compat);
+ }
+ dm = getDisplayMetrics(displayId, daj);
applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
}
if (hasOverrideConfiguration) {
diff --git a/services/core/java/com/android/server/am/RetailDemoModeServiceInternal.java b/core/java/android/app/RetailDemoModeServiceInternal.java
similarity index 74%
rename from services/core/java/com/android/server/am/RetailDemoModeServiceInternal.java
rename to core/java/android/app/RetailDemoModeServiceInternal.java
index 32de03a..7ca214a 100644
--- a/services/core/java/com/android/server/am/RetailDemoModeServiceInternal.java
+++ b/core/java/android/app/RetailDemoModeServiceInternal.java
@@ -14,8 +14,16 @@
* limitations under the License
*/
-package com.android.server.am;
+package android.app;
+/**
+ * Retail Demo Mode Service interface to be used locally inside system server
+ *
+ * @hide Only for use inside system server
+ */
public interface RetailDemoModeServiceInternal {
+ /**
+ * Used to notify RetailDemoModeService of any user activity.
+ */
public void onUserActivity();
}
\ No newline at end of file
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 7cd13ea..55744b9 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -559,7 +559,7 @@
new CachedServiceFetcher<WindowManager>() {
@Override
public WindowManager createService(ContextImpl ctx) {
- return new WindowManagerImpl(ctx.getDisplay());
+ return new WindowManagerImpl(ctx);
}});
registerService(Context.USER_SERVICE, UserManager.class,
diff --git a/core/java/android/app/WallpaperInfo.java b/core/java/android/app/WallpaperInfo.java
index 84a16cf..9d40381f 100644
--- a/core/java/android/app/WallpaperInfo.java
+++ b/core/java/android/app/WallpaperInfo.java
@@ -312,7 +312,12 @@
}
/**
- * Queries whether any metadata should be shown when previewing the wallpaper.
+ * Queries whether any metadata should be shown when previewing the wallpaper. If this value is
+ * set to true, any component that shows a preview of this live wallpaper should also show
+ * accompanying information like {@link #loadLabel},
+ * {@link #loadDescription}, {@link #loadAuthor} and
+ * {@link #loadContextDescription(PackageManager)}, so the user gets to know further information
+ * about this wallpaper.
*
* @return Whether any metadata should be shown when previewing the wallpaper.
*/
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 63afdd8..325a15f 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3030,8 +3030,6 @@
* @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or
* {@code false} otherwise. This carries the risk that any failure of the VPN provider
* could break networking for all apps. This has no effect when clearing.
- * @return {@code true} if the package is set as always-on VPN controller; {@code false}
- * otherwise.
* @throws SecurityException if {@code admin} is not a device or a profile owner.
* @throws NameNotFoundException if {@code vpnPackage} is not installed.
* @throws UnsupportedOperationException if {@code vpnPackage} exists but does not support being
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index 5d4cc6f..a320bbf 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -218,6 +218,14 @@
String[] listAllTransports();
/**
+ * Retrieve the list of whitelisted transport components. Callers do </i>not</i> need
+ * any special permission.
+ *
+ * @return The names of all whitelisted transport components defined by the system.
+ */
+ String[] getTransportWhitelist();
+
+ /**
* Specify the current backup transport. Callers must hold the
* android.permission.BACKUP permission to use this method.
*
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index c4ca82e..5823abf 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -28,6 +28,7 @@
import android.util.Log;
import java.util.ArrayList;
+import java.util.Objects;
/**
* Container of data passed to the {@link android.app.job.JobScheduler} fully encapsulating the
@@ -494,6 +495,20 @@
return mFlags;
}
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof TriggerContentUri)) {
+ return false;
+ }
+ TriggerContentUri t = (TriggerContentUri) o;
+ return Objects.equals(t.mUri, mUri) && t.mFlags == mFlags;
+ }
+
+ @Override
+ public int hashCode() {
+ return (mUri == null ? 0 : mUri.hashCode()) ^ mFlags;
+ }
+
private TriggerContentUri(Parcel in) {
mUri = Uri.CREATOR.createFromParcel(in);
mFlags = in.readInt();
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 720c84a..7961a72 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -305,7 +305,8 @@
*/
public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes,
UsageCallback callback) {
- registerUsageCallback(networkType, subscriberId, thresholdBytes, null /* handler */);
+ registerUsageCallback(networkType, subscriberId, thresholdBytes, callback,
+ null /* handler */);
}
/**
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index f66b5ff..353c640 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -30,8 +30,11 @@
import android.os.RemoteException;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
@@ -114,7 +117,8 @@
private Context mContext;
private ServiceListener mServiceListener;
- private IBluetoothA2dp mService;
+ private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
+ @GuardedBy("mServiceLock") private IBluetoothA2dp mService;
private BluetoothAdapter mAdapter;
final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
@@ -122,25 +126,27 @@
public void onBluetoothStateChange(boolean up) {
if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
if (!up) {
- if (VDBG) Log.d(TAG,"Unbinding service...");
- synchronized (mConnection) {
- try {
- mService = null;
- mContext.unbindService(mConnection);
- } catch (Exception re) {
- Log.e(TAG,"",re);
- }
+ if (VDBG) Log.d(TAG, "Unbinding service...");
+ try {
+ mServiceLock.writeLock().lock();
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG, "", re);
+ } finally {
+ mServiceLock.writeLock().unlock();
}
} else {
- synchronized (mConnection) {
- try {
- if (mService == null) {
- if (VDBG) Log.d(TAG,"Binding service...");
- doBind();
- }
- } catch (Exception re) {
- Log.e(TAG,"",re);
+ try {
+ mServiceLock.readLock().lock();
+ if (mService == null) {
+ if (VDBG) Log.d(TAG,"Binding service...");
+ doBind();
}
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ } finally {
+ mServiceLock.readLock().unlock();
}
}
}
@@ -189,15 +195,16 @@
}
}
- synchronized (mConnection) {
+ try {
+ mServiceLock.writeLock().lock();
if (mService != null) {
- try {
- mService = null;
- mContext.unbindService(mConnection);
- } catch (Exception re) {
- Log.e(TAG,"",re);
- }
+ mService = null;
+ mContext.unbindService(mConnection);
}
+ } catch (Exception re) {
+ Log.e(TAG, "", re);
+ } finally {
+ mServiceLock.writeLock().unlock();
}
}
@@ -229,17 +236,20 @@
*/
public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")");
- if (mService != null && isEnabled() &&
- isValidDevice(device)) {
- try {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
return mService.connect(device);
- } catch (RemoteException e) {
- Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
- return false;
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- return false;
}
/**
@@ -270,17 +280,20 @@
*/
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
- if (mService != null && isEnabled() &&
- isValidDevice(device)) {
- try {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
return mService.disconnect(device);
- } catch (RemoteException e) {
- Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
- return false;
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- return false;
}
/**
@@ -288,16 +301,19 @@
*/
public List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()");
- if (mService != null && isEnabled()) {
- try {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()) {
return mService.getConnectedDevices();
- } catch (RemoteException e) {
- Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
- return new ArrayList<BluetoothDevice>();
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- return new ArrayList<BluetoothDevice>();
}
/**
@@ -305,16 +321,19 @@
*/
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (VDBG) log("getDevicesMatchingStates()");
- if (mService != null && isEnabled()) {
- try {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()) {
return mService.getDevicesMatchingConnectionStates(states);
- } catch (RemoteException e) {
- Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
- return new ArrayList<BluetoothDevice>();
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- return new ArrayList<BluetoothDevice>();
}
/**
@@ -322,17 +341,20 @@
*/
public int getConnectionState(BluetoothDevice device) {
if (VDBG) log("getState(" + device + ")");
- if (mService != null && isEnabled()
- && isValidDevice(device)) {
- try {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
return mService.getConnectionState(device);
- } catch (RemoteException e) {
- Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
- return BluetoothProfile.STATE_DISCONNECTED;
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.STATE_DISCONNECTED;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.STATE_DISCONNECTED;
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- return BluetoothProfile.STATE_DISCONNECTED;
}
/**
@@ -352,21 +374,24 @@
*/
public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")");
- if (mService != null && isEnabled()
- && isValidDevice(device)) {
- if (priority != BluetoothProfile.PRIORITY_OFF &&
- priority != BluetoothProfile.PRIORITY_ON){
- return false;
- }
- try {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ if (priority != BluetoothProfile.PRIORITY_OFF &&
+ priority != BluetoothProfile.PRIORITY_ON) {
+ return false;
+ }
return mService.setPriority(device, priority);
- } catch (RemoteException e) {
- Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
- return false;
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- return false;
}
/**
@@ -385,17 +410,20 @@
@RequiresPermission(Manifest.permission.BLUETOOTH)
public int getPriority(BluetoothDevice device) {
if (VDBG) log("getPriority(" + device + ")");
- if (mService != null && isEnabled()
- && isValidDevice(device)) {
- try {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
return mService.getPriority(device);
- } catch (RemoteException e) {
- Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
- return BluetoothProfile.PRIORITY_OFF;
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.PRIORITY_OFF;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.PRIORITY_OFF;
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- return BluetoothProfile.PRIORITY_OFF;
}
/**
@@ -406,16 +434,19 @@
*/
public boolean isAvrcpAbsoluteVolumeSupported() {
if (DBG) Log.d(TAG, "isAvrcpAbsoluteVolumeSupported");
- if (mService != null && isEnabled()) {
- try {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()) {
return mService.isAvrcpAbsoluteVolumeSupported();
- } catch (RemoteException e) {
- Log.e(TAG, "Error talking to BT service in isAvrcpAbsoluteVolumeSupported()", e);
- return false;
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error talking to BT service in isAvrcpAbsoluteVolumeSupported()", e);
+ return false;
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- return false;
}
/**
@@ -433,16 +464,17 @@
*/
public void adjustAvrcpAbsoluteVolume(int direction) {
if (DBG) Log.d(TAG, "adjustAvrcpAbsoluteVolume");
- if (mService != null && isEnabled()) {
- try {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()) {
mService.adjustAvrcpAbsoluteVolume(direction);
- return;
- } catch (RemoteException e) {
- Log.e(TAG, "Error talking to BT service in adjustAvrcpAbsoluteVolume()", e);
- return;
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error talking to BT service in adjustAvrcpAbsoluteVolume()", e);
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
}
/**
@@ -453,16 +485,17 @@
*/
public void setAvrcpAbsoluteVolume(int volume) {
if (DBG) Log.d(TAG, "setAvrcpAbsoluteVolume");
- if (mService != null && isEnabled()) {
- try {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()) {
mService.setAvrcpAbsoluteVolume(volume);
- return;
- } catch (RemoteException e) {
- Log.e(TAG, "Error talking to BT service in setAvrcpAbsoluteVolume()", e);
- return;
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error talking to BT service in setAvrcpAbsoluteVolume()", e);
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
}
/**
@@ -473,17 +506,20 @@
* @param device BluetoothDevice device
*/
public boolean isA2dpPlaying(BluetoothDevice device) {
- if (mService != null && isEnabled()
- && isValidDevice(device)) {
- try {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
return mService.isA2dpPlaying(device);
- } catch (RemoteException e) {
- Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
- return false;
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- return false;
}
/**
@@ -534,7 +570,12 @@
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
- mService = IBluetoothA2dp.Stub.asInterface(service);
+ try {
+ mServiceLock.writeLock().lock();
+ mService = IBluetoothA2dp.Stub.asInterface(service);
+ } finally {
+ mServiceLock.writeLock().unlock();
+ }
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothProfile.A2DP, BluetoothA2dp.this);
@@ -542,7 +583,12 @@
}
public void onServiceDisconnected(ComponentName className) {
if (DBG) Log.d(TAG, "Proxy object disconnected");
- mService = null;
+ try {
+ mServiceLock.writeLock().lock();
+ mService = null;
+ } finally {
+ mServiceLock.writeLock().unlock();
+ }
if (mServiceListener != null) {
mServiceListener.onServiceDisconnected(BluetoothProfile.A2DP);
}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 9390bcd..47ae687 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -897,28 +897,10 @@
*/
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public boolean enable() {
- int state = BluetoothAdapter.STATE_OFF;
if (isEnabled() == true) {
if (DBG) Log.d(TAG, "enable(): BT is already enabled..!");
return true;
}
- // Use service interface to get the exact state
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- state = mService.getState();
- }
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
-
- if (state == BluetoothAdapter.STATE_BLE_ON) {
- Log.e(TAG, "BT is in BLE_ON State");
- notifyUserAction(true);
- return true;
- }
try {
return mManagerService.enable();
} catch (RemoteException e) {Log.e(TAG, "", e);}
diff --git a/core/java/android/bluetooth/BluetoothSap.java b/core/java/android/bluetooth/BluetoothSap.java
index 014cb22..e70c936 100644
--- a/core/java/android/bluetooth/BluetoothSap.java
+++ b/core/java/android/bluetooth/BluetoothSap.java
@@ -138,7 +138,7 @@
}
boolean doBind() {
- Intent intent = new Intent(IBluetoothMap.class.getName());
+ Intent intent = new Intent(IBluetoothSap.class.getName());
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index ae12c88..ec01bef 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -532,22 +532,19 @@
if(length <= mMaxTxPacketSize) {
mSocketOS.write(b, offset, length);
} else {
- int tmpOffset = offset;
- int tmpLength = mMaxTxPacketSize;
- int endIndex = offset + length;
- boolean done = false;
if(DBG) Log.w(TAG, "WARNING: Write buffer larger than L2CAP packet size!\n"
+ "Packet will be divided into SDU packets of size "
+ mMaxTxPacketSize);
- do{
+ int tmpOffset = offset;
+ int bytesToWrite = length;
+ while (bytesToWrite > 0) {
+ int tmpLength = (bytesToWrite > mMaxTxPacketSize)
+ ? mMaxTxPacketSize
+ : bytesToWrite;
mSocketOS.write(b, tmpOffset, tmpLength);
- tmpOffset += mMaxTxPacketSize;
- if((tmpOffset + mMaxTxPacketSize) > endIndex) {
- tmpLength = endIndex - tmpOffset;
- done = true;
- }
- } while(!done);
-
+ tmpOffset += tmpLength;
+ bytesToWrite -= tmpLength;
+ }
}
} else {
mSocketOS.write(b, offset, length);
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index aeda7a2..c8d8920 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1819,6 +1819,7 @@
* calling app. That is, the returned permissions have been granted
* <em>to</em> the calling app. Only persistable grants taken with
* {@link #takePersistableUriPermission(Uri, int)} are returned.
+ * <p>Note: Some of the returned URIs may not be usable until after the user is unlocked.
*
* @see #takePersistableUriPermission(Uri, int)
* @see #releasePersistableUriPermission(Uri, int)
@@ -1837,6 +1838,7 @@
* calling app. That is, the returned permissions have been granted
* <em>from</em> the calling app. Only grants taken with
* {@link #takePersistableUriPermission(Uri, int)} are returned.
+ * <p>Note: Some of the returned URIs may not be usable until after the user is unlocked.
*/
public @NonNull List<UriPermission> getOutgoingPersistedUriPermissions() {
try {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index ca798f6..3f18ea9 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3615,7 +3615,8 @@
public static final String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
/**
- * TODO Javadoc
+ * Use with {@link #getSystemService} to retrieve a
+ * {@link android.content.pm.ShortcutManager} for accessing the launcher shortcut service.
*
* @see #getSystemService
* @see android.content.pm.ShortcutManager
@@ -4277,6 +4278,11 @@
public abstract DisplayAdjustments getDisplayAdjustments(int displayId);
/**
+ * @hide
+ */
+ public abstract Display getDisplay();
+
+ /**
* Indicates whether this Context is restricted.
*
* @return {@code true} if this Context is restricted, {@code false} otherwise.
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 087ac47..60da63e 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -819,6 +819,14 @@
return mBase.getDisplayAdjustments(displayId);
}
+ /**
+ * @hide
+ */
+ @Override
+ public Display getDisplay() {
+ return mBase.getDisplay();
+ }
+
@Override
public Context createDeviceProtectedStorageContext() {
return mBase.createDeviceProtectedStorageContext();
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index df2c6fc..c140f1bd5 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1556,7 +1556,7 @@
/**
* Used as an int extra field with {@link #ACTION_INSTALL_PACKAGE} and
- * {@link} #ACTION_VIEW} to indicate the uid of the package that initiated the install
+ * {@link #ACTION_VIEW} to indicate the uid of the package that initiated the install
* @hide
*/
@SystemApi
diff --git a/core/java/android/content/pm/EphemeralResolveInfo.java b/core/java/android/content/pm/EphemeralResolveInfo.java
index 2b9cfa0..fc3b958 100644
--- a/core/java/android/content/pm/EphemeralResolveInfo.java
+++ b/core/java/android/content/pm/EphemeralResolveInfo.java
@@ -27,6 +27,7 @@
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
/**
* Information about an ephemeral application.
@@ -52,7 +53,7 @@
throw new IllegalArgumentException();
}
- mDigest = new EphemeralDigest(uri, -1);
+ mDigest = new EphemeralDigest(uri, 0xFFFFFFFF, -1);
mFilters.addAll(filters);
mPackageName = packageName;
}
@@ -134,7 +135,7 @@
/** The first 4 bytes of the domain hashes */
private final int[] mDigestPrefix;
- public EphemeralDigest(@NonNull Uri uri, int maxDigests) {
+ public EphemeralDigest(@NonNull Uri uri, int digestMask, int maxDigests) {
if (uri == null) {
throw new IllegalArgumentException();
}
@@ -142,17 +143,18 @@
mDigestPrefix = new int[mDigestBytes.length];
for (int i = 0; i < mDigestBytes.length; i++) {
mDigestPrefix[i] =
- (mDigestBytes[i][0] & 0xFF) << 24
- | (mDigestBytes[i][1] & 0xFF) << 16
- | (mDigestBytes[i][2] & 0xFF) << 8
- | (mDigestBytes[i][3] & 0xFF) << 0;
+ ((mDigestBytes[i][0] & 0xFF) << 24
+ | (mDigestBytes[i][1] & 0xFF) << 16
+ | (mDigestBytes[i][2] & 0xFF) << 8
+ | (mDigestBytes[i][3] & 0xFF) << 0)
+ & digestMask;
}
}
private static byte[][] generateDigest(Uri uri, int maxDigests) {
ArrayList<byte[]> digests = new ArrayList<>();
try {
- final String host = uri.getHost();
+ final String host = uri.getHost().toLowerCase(Locale.ENGLISH);
final MessageDigest digest = MessageDigest.getInstance(SHA_ALGORITHM);
if (maxDigests <= 0) {
final byte[] hostBytes = host.getBytes();
diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl
index 1c373f9..7ba1b8b 100644
--- a/core/java/android/content/pm/IShortcutService.aidl
+++ b/core/java/android/content/pm/IShortcutService.aidl
@@ -46,7 +46,7 @@
void enableShortcuts(String packageName, in List shortcutIds, int userId);
- int getMaxDynamicShortcutCount(String packageName, int userId);
+ int getMaxShortcutCountForActivity(String packageName, int userId);
int getRemainingCallCount(String packageName, int userId);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 6cb50fc..d57968f 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -171,8 +171,9 @@
* as defined in {@link #hasShortcutHostPermission()}, will receive it.
*
* @param packageName The name of the package that has the shortcuts.
- * @param shortcuts all shortcuts from the package (dynamic and/or pinned). Only "key"
- * information will be provided, as defined in {@link ShortcutInfo#hasKeyFieldsOnly()}.
+ * @param shortcuts all shortcuts from the package (dynamic, manifest and/or pinned).
+ * Only "key" information will be provided, as defined in
+ * {@link ShortcutInfo#hasKeyFieldsOnly()}.
* @param user The UserHandle of the profile that generated the change.
*/
public void onShortcutsChanged(@NonNull String packageName,
@@ -187,17 +188,37 @@
/**
* Include dynamic shortcuts in the result.
*/
- public static final int FLAG_GET_DYNAMIC = 1 << 0;
+ public static final int FLAG_MATCH_DYNAMIC = 1 << 0;
+
+ /** @hide kept for unit tests */
+ @Deprecated
+ public static final int FLAG_GET_DYNAMIC = FLAG_MATCH_DYNAMIC;
/**
* Include pinned shortcuts in the result.
*/
- public static final int FLAG_GET_PINNED = 1 << 1;
+ public static final int FLAG_MATCH_PINNED = 1 << 1;
+
+ /** @hide kept for unit tests */
+ @Deprecated
+ public static final int FLAG_GET_PINNED = FLAG_MATCH_PINNED;
/**
* Include manifest shortcuts in the result.
*/
- public static final int FLAG_GET_MANIFEST = 1 << 3;
+ public static final int FLAG_MATCH_MANIFEST = 1 << 3;
+
+ /** @hide kept for unit tests */
+ @Deprecated
+ public static final int FLAG_GET_MANIFEST = FLAG_MATCH_MANIFEST;
+
+ /** @hide */
+ public static final int FLAG_MATCH_ALL_KINDS =
+ FLAG_GET_DYNAMIC | FLAG_GET_PINNED | FLAG_GET_MANIFEST;
+
+ /** @hide kept for unit tests */
+ @Deprecated
+ public static final int FLAG_GET_ALL_KINDS = FLAG_MATCH_ALL_KINDS;
/**
* Requests "key" fields only. See {@link ShortcutInfo#hasKeyFieldsOnly()} for which
@@ -208,9 +229,9 @@
/** @hide */
@IntDef(flag = true,
value = {
- FLAG_GET_DYNAMIC,
- FLAG_GET_PINNED,
- FLAG_GET_MANIFEST,
+ FLAG_MATCH_DYNAMIC,
+ FLAG_MATCH_PINNED,
+ FLAG_MATCH_MANIFEST,
FLAG_GET_KEY_FIELDS_ONLY,
})
@Retention(RetentionPolicy.SOURCE)
@@ -480,12 +501,13 @@
* @hide // No longer used. Use getShortcuts() instead. Kept for unit tests.
*/
@Nullable
+ @Deprecated
public List<ShortcutInfo> getShortcutInfo(@NonNull String packageName,
@NonNull List<String> ids, @NonNull UserHandle user) {
final ShortcutQuery q = new ShortcutQuery();
q.setPackage(packageName);
q.setShortcutIds(ids);
- q.setQueryFlags(ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED);
+ q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
return getShortcuts(q, user);
}
@@ -514,6 +536,7 @@
/**
* @hide kept for testing.
*/
+ @Deprecated
public int getShortcutIconResId(@NonNull ShortcutInfo shortcut) {
return shortcut.getIconResourceId();
}
@@ -521,25 +544,20 @@
/**
* @hide kept for testing.
*/
+ @Deprecated
public int getShortcutIconResId(@NonNull String packageName, @NonNull String shortcutId,
@NonNull UserHandle user) {
final ShortcutQuery q = new ShortcutQuery();
q.setPackage(packageName);
q.setShortcutIds(Arrays.asList(shortcutId));
- q.setQueryFlags(ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED);
+ q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
final List<ShortcutInfo> shortcuts = getShortcuts(q, user);
return shortcuts.size() > 0 ? shortcuts.get(0).getIconResourceId() : 0;
}
/**
- * Return the icon as {@link ParcelFileDescriptor}, when it's stored as a file
- * (i.e. when {@link ShortcutInfo#hasIconFile()} returns {@code true}).
- *
- * <p>Callers must be allowed to access the shortcut information, as defined in {@link
- * #hasShortcutHostPermission()}.
- *
- * @param shortcut The target shortcut.
+ * @hide internal/unit tests only
*/
public ParcelFileDescriptor getShortcutIconFd(
@NonNull ShortcutInfo shortcut) {
@@ -548,15 +566,7 @@
}
/**
- * Return the icon as {@link ParcelFileDescriptor}, when it's stored as a file
- * (i.e. when {@link ShortcutInfo#hasIconFile()} returns {@code true}).
- *
- * <p>Callers must be allowed to access the shortcut information, as defined in {@link
- * #hasShortcutHostPermission()}.
- *
- * @param packageName The target package name.
- * @param shortcutId The ID of the shortcut to lad rom.
- * @param user The UserHandle of the profile.
+ * @hide internal/unit tests only
*/
public ParcelFileDescriptor getShortcutIconFd(
@NonNull String packageName, @NonNull String shortcutId, @NonNull UserHandle user) {
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 896fa43..35370f0 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -30,6 +30,7 @@
import android.os.Parcelable;
import android.os.PersistableBundle;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
@@ -38,6 +39,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.List;
import java.util.Set;
// TODO Enhance javadoc
@@ -245,7 +247,7 @@
mTextResId = b.mTextResId;
mDisabledMessage = b.mDisabledMessage;
mDisabledMessageResId = b.mDisabledMessageResId;
- mCategories = clone(b.mCategories);
+ mCategories = cloneCategories(b.mCategories);
mIntent = b.mIntent;
if (mIntent != null) {
final Bundle intentExtras = mIntent.getExtras();
@@ -259,8 +261,17 @@
updateTimestamp();
}
- private <T> ArraySet<T> clone(Set<T> source) {
- return (source == null) ? null : new ArraySet<>(source);
+ private ArraySet<String> cloneCategories(Set<String> source) {
+ if (source == null) {
+ return null;
+ }
+ final ArraySet<String> ret = new ArraySet<>(source.size());
+ for (CharSequence s : source) {
+ if (!TextUtils.isEmpty(s)) {
+ ret.add(s.toString().intern());
+ }
+ }
+ return ret;
}
/**
@@ -284,6 +295,7 @@
mUserId = source.mUserId;
mId = source.mId;
mPackageName = source.mPackageName;
+ mActivity = source.mActivity;
mFlags = source.mFlags;
mLastChangedTimestamp = source.mLastChangedTimestamp;
@@ -291,7 +303,6 @@
mIconResId = source.mIconResId;
if ((cloneFlags & CLONE_REMOVE_NON_KEY_INFO) == 0) {
- mActivity = source.mActivity;
if ((cloneFlags & CLONE_REMOVE_ICON) == 0) {
mIcon = source.mIcon;
@@ -304,7 +315,7 @@
mTextResId = source.mTextResId;
mDisabledMessage = source.mDisabledMessage;
mDisabledMessageResId = source.mDisabledMessageResId;
- mCategories = clone(source.mCategories);
+ mCategories = cloneCategories(source.mCategories);
if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) {
mIntent = source.mIntent;
mIntentPersistableExtras = source.mIntentPersistableExtras;
@@ -614,7 +625,7 @@
mDisabledMessageResName = null;
}
if (source.mCategories != null) {
- mCategories = clone(source.mCategories);
+ mCategories = cloneCategories(source.mCategories);
}
if (source.mIntent != null) {
mIntent = source.mIntent;
@@ -684,24 +695,43 @@
private PersistableBundle mExtras;
- /** Constructor. */
+ /**
+ * Old style constructor. STOPSHIP hide it before launch.
+ */
+ @Deprecated
public Builder(Context context) {
mContext = context;
}
/**
- * Sets the ID of the shortcut. This is a mandatory field.
+ * Used with the old style constructor, kept for unit tests. STOPSHIP hide it before launch.
*/
@NonNull
+ @Deprecated
public Builder setId(@NonNull String id) {
- mId = Preconditions.checkStringNotEmpty(id, "id");
+ mId = Preconditions.checkStringNotEmpty(id, "id cannot be empty");
return this;
}
/**
- * Optionally sets the target activity. If it's not set, and if the caller application
- * has multiple launcher icons, this shortcut will be shown on all those icons.
- * If it's set, this shortcut will be only shown on this activity.
+ * Constructor.
+ *
+ * @param context Client context.
+ * @param id ID of the shortcut.
+ */
+ public Builder(Context context, String id) {
+ mContext = context;
+ mId = Preconditions.checkStringNotEmpty(id, "id cannot be empty");
+ }
+
+ /**
+ * Sets the target activity. A shortcut will be shown with this activity on the launcher.
+ *
+ * <p>Only "main" activities -- i.e. ones with an intent filter for
+ * {@link Intent#ACTION_MAIN} and {@link Intent#CATEGORY_LAUNCHER} can be target activities.
+ *
+ * <p>By default, the first main activity defined in the application manifest will be
+ * the target.
*
* <p>The package name of the target activity must match the package name of the shortcut
* publisher.
@@ -711,23 +741,23 @@
*/
@NonNull
public Builder setActivity(@NonNull ComponentName activity) {
- mActivity = Preconditions.checkNotNull(activity, "activity");
+ mActivity = Preconditions.checkNotNull(activity, "activity cannot be null");
return this;
}
/**
- * Optionally sets an icon.
+ * Sets an icon.
*
* <ul>
* <li>Tints set by {@link Icon#setTint} or {@link Icon#setTintList} are not supported.
* <li>Bitmaps and resources are supported, but "content:" URIs are not supported.
* </ul>
*
- * <p>For performance reasons, icons will <b>NOT</b> be available on instances
- * returned by {@link ShortcutManager} or {@link LauncherApps}. Launcher applications
- * can use {@link ShortcutInfo#getIconResourceId()} if {@link #hasIconResource()} is true.
- * Otherwise, if {@link #hasIconFile()} is true, use
- * {@link LauncherApps#getShortcutIconFd} to load the image.
+ * <p>For performance and security reasons, icons will <b>NOT</b> be available on instances
+ * returned by {@link ShortcutManager} or {@link LauncherApps}. Default launcher application
+ * can use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}
+ * or {@link LauncherApps#getShortcutBadgedIconDrawable(ShortcutInfo, int)} to fetch
+ * shortcut icons.
*/
@NonNull
public Builder setIcon(Icon icon) {
@@ -739,6 +769,7 @@
* @hide We don't support resource strings for dynamic shortcuts for now. (But unit tests
* use it.)
*/
+ @Deprecated
public Builder setShortLabelResId(int shortLabelResId) {
Preconditions.checkState(mTitle == null, "shortLabel already set");
mTitleResId = shortLabelResId;
@@ -746,15 +777,18 @@
}
/**
- * Sets the short title of a shortcut. This is a mandatory field.
+ * Sets the short title of a shortcut.
+ *
+ * <p>This is a mandatory field, unless it's passed to
+ * {@link ShortcutManager#updateShortcuts(List)}.
*
* <p>This field is intended for a concise description of a shortcut displayed under
* an icon. The recommend max length is 10 characters.
*/
@NonNull
- public Builder setShortLabel(@NonNull String shortLabel) {
+ public Builder setShortLabel(@NonNull CharSequence shortLabel) {
Preconditions.checkState(mTitleResId == 0, "shortLabelResId already set");
- mTitle = Preconditions.checkStringNotEmpty(shortLabel, "shortLabel");
+ mTitle = Preconditions.checkStringNotEmpty(shortLabel, "shortLabel cannot be empty");
return this;
}
@@ -762,6 +796,7 @@
* @hide We don't support resource strings for dynamic shortcuts for now. (But unit tests
* use it.)
*/
+ @Deprecated
public Builder setLongLabelResId(int longLabelResId) {
Preconditions.checkState(mText == null, "longLabel already set");
mTextResId = longLabelResId;
@@ -769,35 +804,39 @@
}
/**
- * Sets the text of a shortcut. This is an optional field.
+ * Sets the text of a shortcut.
*
* <p>This field is intended to be more descriptive than the shortcut title. The launcher
* shows this instead of the short title, when it has enough space.
* The recommend max length is 25 characters.
*/
@NonNull
- public Builder setLongLabel(@NonNull String longLabel) {
+ public Builder setLongLabel(@NonNull CharSequence longLabel) {
Preconditions.checkState(mTextResId == 0, "longLabelResId already set");
- mText = Preconditions.checkStringNotEmpty(longLabel, "longLabel");
+ mText = Preconditions.checkStringNotEmpty(longLabel, "longLabel cannot be empty");
return this;
}
/** @hide -- old signature, the internal code still uses it. */
- public Builder setTitle(@NonNull String value) {
+ @Deprecated
+ public Builder setTitle(@NonNull CharSequence value) {
return setShortLabel(value);
}
/** @hide -- old signature, the internal code still uses it. */
+ @Deprecated
public Builder setTitleResId(int value) {
return setShortLabelResId(value);
}
/** @hide -- old signature, the internal code still uses it. */
- public Builder setText(@NonNull String value) {
+ @Deprecated
+ public Builder setText(@NonNull CharSequence value) {
return setLongLabel(value);
}
/** @hide -- old signature, the internal code still uses it. */
+ @Deprecated
public Builder setTextResId(int value) {
return setLongLabelResId(value);
}
@@ -806,6 +845,7 @@
* @hide We don't support resource strings for dynamic shortcuts for now. (But unit tests
* use it.)
*/
+ @Deprecated
public Builder setDisabledMessageResId(int disabledMessageResId) {
Preconditions.checkState(mDisabledMessage == null, "disabledMessage already set");
mDisabledMessageResId = disabledMessageResId;
@@ -813,11 +853,12 @@
}
@NonNull
- public Builder setDisabledMessage(@NonNull String disabledMessage) {
+ public Builder setDisabledMessage(@NonNull CharSequence disabledMessage) {
Preconditions.checkState(
mDisabledMessageResId == 0, "disabledMessageResId already set");
mDisabledMessage =
- Preconditions.checkStringNotEmpty(disabledMessage, "disabledMessage");
+ Preconditions.checkStringNotEmpty(disabledMessage,
+ "disabledMessage cannot be empty");
return this;
}
@@ -839,8 +880,8 @@
*/
@NonNull
public Builder setIntent(@NonNull Intent intent) {
- mIntent = Preconditions.checkNotNull(intent, "intent");
- Preconditions.checkNotNull(mIntent.getAction(), "Intent action must be set");
+ mIntent = Preconditions.checkNotNull(intent, "intent cannot be null");
+ Preconditions.checkNotNull(mIntent.getAction(), "intent's action must be set");
return this;
}
@@ -857,7 +898,9 @@
}
/**
- * Optional values that applications can set. Applications can store any meta-data of
+ * Extras that application can set to any purposes.
+ *
+ * <p>Applications can store any meta-data of
* shortcuts in this, and retrieve later from {@link ShortcutInfo#getExtras()}.
*/
@NonNull
@@ -905,6 +948,11 @@
return mActivity;
}
+ /** @hide */
+ public void setActivity(ComponentName activity) {
+ mActivity = activity;
+ }
+
/**
* Icon.
*
@@ -921,22 +969,26 @@
/** @hide -- old signature, the internal code still uses it. */
@Nullable
+ @Deprecated
public CharSequence getTitle() {
return mTitle;
}
/** @hide -- old signature, the internal code still uses it. */
+ @Deprecated
public int getTitleResId() {
return mTitleResId;
}
/** @hide -- old signature, the internal code still uses it. */
@Nullable
+ @Deprecated
public CharSequence getText() {
return mText;
}
/** @hide -- old signature, the internal code still uses it. */
+ @Deprecated
public int getTextResId() {
return mTextResId;
}
@@ -1084,7 +1136,7 @@
}
/**
- * Optional values that application can set.
+ * Extras that application can set to any purposes.
*/
@Nullable
public PersistableBundle getExtras() {
@@ -1158,10 +1210,16 @@
* <p>NOTE this is whether a shortcut is published from the <b>current version's</b>
* AndroidManifest.xml.
*/
- public boolean isManifestShortcut() {
+ public boolean isDeclaredInManifest() {
return hasFlags(FLAG_MANIFEST);
}
+ /** @hide kept for unit tests */
+ @Deprecated
+ public boolean isManifestShortcut() {
+ return isDeclaredInManifest();
+ }
+
/**
* @return true if pinned but neither dynamic nor manifest.
* @hide
@@ -1181,7 +1239,7 @@
*
* <p>All manifest shortcuts are immutable. When a manifest shortcut is pinned and then
* disabled because the app is upgraded and its AndroidManifest.xml no longer publishes it,
- * {@link #isManifestShortcut} returns {@code false}, but it is still immutable.
+ * {@link #isDeclaredInManifest()} returns {@code false}, but it is still immutable.
*
* <p>All shortcuts originally published via the {@link ShortcutManager} APIs
* are all mutable.
@@ -1211,7 +1269,7 @@
/**
* Return whether a shortcut's icon is a resource in the owning package.
*
- * @see LauncherApps#getShortcutIconResId(ShortcutInfo)
+ * @hide internal/unit tests only
*/
public boolean hasIconResource() {
return hasFlags(FLAG_HAS_ICON_RES);
@@ -1230,7 +1288,7 @@
/**
* Return whether a shortcut's icon is stored as a file.
*
- * @see LauncherApps#getShortcutIconFd(ShortcutInfo)
+ * @hide internal/unit tests only
*/
public boolean hasIconFile() {
return hasFlags(FLAG_HAS_ICON_FILE);
@@ -1242,18 +1300,21 @@
* <ul>
* <li>{@link #getId()}
* <li>{@link #getPackage()}
+ * <li>{@link #getActivity()}
* <li>{@link #getLastChangedTimestamp()}
* <li>{@link #isDynamic()}
* <li>{@link #isPinned()}
- * <li>{@link #hasIconResource()}
- * <li>{@link #hasIconFile()}
+ * <li>{@link #isDeclaredInManifest()}
+ * <li>{@link #isImmutable()}
+ * <li>{@link #isEnabled()}
+ * <li>{@link #getUserHandle()}
* </ul>
*/
public boolean hasKeyFieldsOnly() {
return hasFlags(FLAG_KEY_FIELDS_ONLY);
}
- /** TODO Javadoc */
+ /** @hide */
public boolean hasStringResourcesResolved() {
return hasFlags(FLAG_STRINGS_RESOLVED);
}
@@ -1284,6 +1345,7 @@
/**
* Get the resource ID for the icon, valid only when {@link #hasIconResource()} } is true.
+ * @hide internal / tests only.
*/
public int getIconResourceId() {
return mIconResId;
@@ -1355,6 +1417,37 @@
mIconResName = iconResName;
}
+ /**
+ * Replaces the intent
+ *
+ * @throws IllegalArgumentException when extra is not compatible with {@link PersistableBundle}.
+ *
+ * @hide
+ */
+ public void setIntent(Intent intent) throws IllegalArgumentException {
+ Preconditions.checkNotNull(intent);
+
+ final Bundle intentExtras = intent.getExtras();
+
+ mIntent = intent;
+
+ if (intentExtras != null) {
+ intent.replaceExtras((Bundle) null);
+ mIntentPersistableExtras = new PersistableBundle(intentExtras);
+ } else {
+ mIntentPersistableExtras = null;
+ }
+ }
+
+ /**
+ * Replaces the categories.
+ *
+ * @hide
+ */
+ public void setCategories(Set<String> categories) {
+ mCategories = cloneCategories(categories);
+ }
+
private ShortcutInfo(Parcel source) {
final ClassLoader cl = getClass().getClassLoader();
@@ -1362,6 +1455,14 @@
mId = source.readString();
mPackageName = source.readString();
mActivity = source.readParcelable(cl);
+ mFlags = source.readInt();
+ mIconResId = source.readInt();
+ mLastChangedTimestamp = source.readLong();
+
+ if (source.readInt() == 0) {
+ return; // key information only.
+ }
+
mIcon = source.readParcelable(cl);
mTitle = source.readCharSequence();
mTitleResId = source.readInt();
@@ -1373,9 +1474,6 @@
mIntentPersistableExtras = source.readParcelable(cl);
mRank = source.readInt();
mExtras = source.readParcelable(cl);
- mLastChangedTimestamp = source.readLong();
- mFlags = source.readInt();
- mIconResId = source.readInt();
mBitmapPath = source.readString();
mIconResName = source.readString();
@@ -1400,6 +1498,16 @@
dest.writeString(mId);
dest.writeString(mPackageName);
dest.writeParcelable(mActivity, flags);
+ dest.writeInt(mFlags);
+ dest.writeInt(mIconResId);
+ dest.writeLong(mLastChangedTimestamp);
+
+ if (hasKeyFieldsOnly()) {
+ dest.writeInt(0);
+ return;
+ }
+ dest.writeInt(1);
+
dest.writeParcelable(mIcon, flags);
dest.writeCharSequence(mTitle);
dest.writeInt(mTitleResId);
@@ -1412,9 +1520,6 @@
dest.writeParcelable(mIntentPersistableExtras, flags);
dest.writeInt(mRank);
dest.writeParcelable(mExtras, flags);
- dest.writeLong(mLastChangedTimestamp);
- dest.writeInt(mFlags);
- dest.writeInt(mIconResId);
dest.writeString(mBitmapPath);
dest.writeString(mIconResName);
@@ -1591,7 +1696,7 @@
mDisabledMessage = disabledMessage;
mDisabledMessageResId = disabledMessageResId;
mDisabledMessageResName = disabledMessageResName;
- mCategories = clone(categories);
+ mCategories = cloneCategories(categories);
mIntent = intent;
mIntentPersistableExtras = intentPersistableExtras;
mRank = rank;
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index eaccb3a..3ccdef1 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -17,6 +17,7 @@
import android.annotation.NonNull;
import android.annotation.TestApi;
+import android.annotation.UserIdInt;
import android.app.usage.UsageStatsManager;
import android.content.Context;
import android.os.RemoteException;
@@ -295,12 +296,13 @@
}
/**
- * Return the max number of dynamic shortcuts + manifest shortcuts that each launcehr icon
+ * Return the max number of dynamic shortcuts + manifest shortcuts that each launcher icon
* can have at a time.
*/
public int getMaxShortcutCountForActivity() {
try {
- return mService.getMaxDynamicShortcutCount(mContext.getPackageName(), injectMyUserId());
+ return mService.getMaxShortcutCountForActivity(
+ mContext.getPackageName(), injectMyUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -379,6 +381,22 @@
}
}
+ /**
+ * Called internally when an application is considered to have come to foreground
+ * even when technically it's not. This method resets the throttling for this package.
+ * For example, when the user sends an "inline reply" on an notification, the system UI will
+ * call it.
+ *
+ * @hide
+ */
+ public void onApplicationActive(@NonNull String packageName, @UserIdInt int userId) {
+ try {
+ mService.onApplicationActive(packageName, userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/** @hide injection point */
@VisibleForTesting
protected int injectMyUserId() {
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 6f43d99..b2d518c 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1543,27 +1543,41 @@
* @hide
*/
public static String localesToResourceQualifier(LocaleList locs) {
- StringBuilder sb = new StringBuilder();
+ final StringBuilder sb = new StringBuilder();
for (int i = 0; i < locs.size(); i++) {
- Locale loc = locs.get(i);
- boolean l = (loc.getLanguage().length() != 0);
- boolean c = (loc.getCountry().length() != 0);
- boolean s = (loc.getScript().length() != 0);
- boolean v = (loc.getVariant().length() != 0);
- // TODO: take script and extensions into account
- if (l) {
- if (sb.length() != 0) {
- sb.append(",");
- }
+ final Locale loc = locs.get(i);
+ final int l = loc.getLanguage().length();
+ if (l == 0) {
+ continue;
+ }
+ final int s = loc.getScript().length();
+ final int c = loc.getCountry().length();
+ final int v = loc.getVariant().length();
+ // We ignore locale extensions, since they are not supported by AAPT
+
+ if (sb.length() != 0) {
+ sb.append(",");
+ }
+ if (l == 2 && s == 0 && (c == 0 || c == 2) && v == 0) {
+ // Traditional locale format: xx or xx-rYY
sb.append(loc.getLanguage());
- if (c) {
+ if (c == 2) {
sb.append("-r").append(loc.getCountry());
- if (s) {
- sb.append("-s").append(loc.getScript());
- if (v) {
- sb.append("-v").append(loc.getVariant());
- }
- }
+ }
+ } else {
+ sb.append("b+");
+ sb.append(loc.getLanguage());
+ if (s != 0) {
+ sb.append("+");
+ sb.append(loc.getScript());
+ }
+ if (c != 0) {
+ sb.append("+");
+ sb.append(loc.getCountry());
+ }
+ if (v != 0) {
+ sb.append("+");
+ sb.append(loc.getVariant());
}
}
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 54a5968..8d3940c 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -51,6 +51,7 @@
import android.util.LongSparseArray;
import android.util.Pools.SynchronizedPool;
import android.util.TypedValue;
+import android.view.DisplayAdjustments;
import android.view.ViewDebug;
import android.view.ViewHierarchyEncoder;
@@ -208,8 +209,7 @@
*/
public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
this(null);
- mResourcesImpl = new ResourcesImpl(assets, metrics, config,
- CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO);
+ mResourcesImpl = new ResourcesImpl(assets, metrics, config, new DisplayAdjustments());
}
/**
@@ -237,7 +237,7 @@
config.setToDefaults();
mResourcesImpl = new ResourcesImpl(AssetManager.getSystem(), metrics, config,
- CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO);
+ new DisplayAdjustments());
}
/**
@@ -1800,6 +1800,11 @@
return mResourcesImpl.getDisplayMetrics();
}
+ /** @hide */
+ public DisplayAdjustments getDisplayAdjustments() {
+ return mResourcesImpl.getDisplayAdjustments();
+ }
+
/**
* Return the current configuration that is in effect for this resource
* object. The returned object should be treated as read-only.
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 000751e..aa803902 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -44,6 +44,8 @@
import android.util.Slog;
import android.util.TypedValue;
import android.util.Xml;
+import android.view.Display;
+import android.view.DisplayAdjustments;
import java.io.InputStream;
import java.util.Arrays;
@@ -111,12 +113,12 @@
final AssetManager mAssets;
- final DisplayMetrics mMetrics = new DisplayMetrics();
+ private final DisplayMetrics mMetrics = new DisplayMetrics();
+ private final DisplayAdjustments mDisplayAdjustments;
private PluralRules mPluralRule;
private final Configuration mConfiguration = new Configuration();
- private CompatibilityInfo mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
static {
sPreloadedDrawables = new LongSparseArray[2];
@@ -132,16 +134,22 @@
* selecting/computing resource values.
* @param config Desired device configuration to consider when
* selecting/computing resource values (optional).
- * @param compatInfo this resource's compatibility info. Must not be null.
+ * @param displayAdjustments this resource's Display override and compatibility info.
+ * Must not be null.
*/
- public ResourcesImpl(AssetManager assets, DisplayMetrics metrics, Configuration config,
- CompatibilityInfo compatInfo) {
+ public ResourcesImpl(@NonNull AssetManager assets, @Nullable DisplayMetrics metrics,
+ @Nullable Configuration config, @NonNull DisplayAdjustments displayAdjustments) {
mAssets = assets;
mMetrics.setToDefaults();
- updateConfiguration(config, metrics, compatInfo);
+ mDisplayAdjustments = displayAdjustments;
+ updateConfiguration(config, metrics, displayAdjustments.getCompatibilityInfo());
mAssets.ensureStringBlocks();
}
+ public DisplayAdjustments getDisplayAdjustments() {
+ return mDisplayAdjustments;
+ }
+
public AssetManager getAssets() {
return mAssets;
}
@@ -161,7 +169,7 @@
}
CompatibilityInfo getCompatibilityInfo() {
- return mCompatibilityInfo;
+ return mDisplayAdjustments.getCompatibilityInfo();
}
private PluralRules getPluralRule() {
@@ -316,12 +324,13 @@
synchronized (mAccessLock) {
if (false) {
Slog.i(TAG, "**** Updating config of " + this + ": old config is "
- + mConfiguration + " old compat is " + mCompatibilityInfo);
+ + mConfiguration + " old compat is "
+ + mDisplayAdjustments.getCompatibilityInfo());
Slog.i(TAG, "**** Updating config of " + this + ": new config is "
+ config + " new compat is " + compat);
}
if (compat != null) {
- mCompatibilityInfo = compat;
+ mDisplayAdjustments.setCompatibilityInfo(compat);
}
if (metrics != null) {
mMetrics.setTo(metrics);
@@ -335,7 +344,7 @@
// it would be cleaner and more maintainable to just be
// consistently dealing with a compatible display everywhere in
// the framework.
- mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
+ mDisplayAdjustments.getCompatibilityInfo().applyToDisplayMetrics(mMetrics);
final @Config int configChanges = calcConfigChanges(config);
@@ -409,7 +418,8 @@
if (DEBUG_CONFIG) {
Slog.i(TAG, "**** Updating config of " + this + ": final config is "
- + mConfiguration + " final compat is " + mCompatibilityInfo);
+ + mConfiguration + " final compat is "
+ + mDisplayAdjustments.getCompatibilityInfo());
}
mDrawableCache.onConfigurationChange(configChanges);
@@ -449,7 +459,7 @@
density = mMetrics.noncompatDensityDpi;
}
- mCompatibilityInfo.applyToConfiguration(density, mTmpConfig);
+ mDisplayAdjustments.getCompatibilityInfo().applyToConfiguration(density, mTmpConfig);
if (mTmpConfig.getLocales().isEmpty()) {
mTmpConfig.setLocales(LocaleList.getDefault());
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 0f07419..c9ae69c 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -20,8 +20,6 @@
import android.annotation.SystemApi;
import android.os.Build;
-import java.util.UUID;
-
/**
* Class representing a sensor. Use {@link SensorManager#getSensorList} to get
* the list of available Sensors.
@@ -806,7 +804,7 @@
private String mRequiredPermission;
private int mMaxDelay;
private int mFlags;
- private UUID mUuid;
+ private int mId;
Sensor() {
}
@@ -895,34 +893,28 @@
}
/**
- * @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.
+ * Do not use.
+ *
+ * This method throws an UnsupportedOperationException.
+ *
+ * Use getId() if you want a unique ID.
+ *
+ * @see getId
*
* @hide
*/
@SystemApi
- public UUID getUuid() {
- return mUuid;
+ public java.util.UUID getUuid() {
+ throw new UnsupportedOperationException();
}
/**
- * @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.
+ * @return The sensor id that will be unique for the same app unless the device is factory
+ * reset. Return value of 0 means this sensor does not support this function; 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.equals(ALL_0_UUID)) {
- return 0;
- } else if (mUuid.equals(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;
- }
+ return mId;
}
/**
@@ -1038,10 +1030,6 @@
+ ", 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.
@@ -1141,24 +1129,17 @@
}
/**
- * Sets the UUID associated with the sensor.
+ * Sets the ID associated with the sensor.
+ *
+ * The method name is misleading; while this ID is based on the UUID,
+ * we do not pass in the actual UUID.
*
* NOTE: to be used only by native bindings in SensorManager.
*
- * @see #getUuid
- * @see UUID
+ * @see #getId
*/
private void setUuid(long msb, long lsb) {
- // reuse static object if possible
- if (msb == lsb) {
- if (msb == 0L) {
- mUuid = ALL_0_UUID;
- return;
- } else if (msb == ~0L) {
- mUuid = ALL_F_UUID;
- return;
- }
- }
- mUuid = new UUID(msb, lsb);
+ // TODO(b/29547335): Rename this method to setId.
+ mId = (int)msb;
}
}
diff --git a/core/java/android/hardware/input/InputManagerInternal.java b/core/java/android/hardware/input/InputManagerInternal.java
index 10fc8e6..01a5404 100644
--- a/core/java/android/hardware/input/InputManagerInternal.java
+++ b/core/java/android/hardware/input/InputManagerInternal.java
@@ -59,4 +59,9 @@
* @param deviceId The id of input device.
*/
public abstract void toggleCapsLock(int deviceId);
+
+ /**
+ * Set whether the input stack should deliver pulse gesture events when the device is asleep.
+ */
+ public abstract void setPulseGestureEnabled(boolean enabled);
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 4799773..8e0e0b0 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -23,6 +23,7 @@
import android.annotation.DrawableRes;
import android.annotation.IntDef;
import android.annotation.MainThread;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.Dialog;
import android.content.Context;
@@ -65,6 +66,7 @@
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputBinding;
import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputContentInfo;
import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
@@ -2598,6 +2600,39 @@
}
/**
+ * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access
+ * permission to the content.
+ *
+ * <p>Make sure that the content provider owning the Uri sets the
+ * {@link android.R.styleable#AndroidManifestProvider_grantUriPermissions
+ * grantUriPermissions} attribute in its manifest or included the
+ * {@link android.R.styleable#AndroidManifestGrantUriPermission
+ * <grant-uri-permissions>} tag. Otherwise {@link InputContentInfo#requestPermission()}
+ * can fail.</p>
+ *
+ * <p>Although calling this API is allowed only for the IME that is currently selected, the
+ * client is able to request a temporary read-only access even after the current IME is switched
+ * to any other IME as long as the client keeps {@link InputContentInfo} object.</p>
+ *
+ * @param inputContentInfo Content to be temporarily exposed from the input method to the
+ * application.
+ * This cannot be {@code null}.
+ * @param editorInfo The editor that receives {@link InputContentInfo}.
+ * @return {@code false} if we cannot allow a temporary access permission.
+ */
+ public final boolean exposeContent(@NonNull InputContentInfo inputContentInfo,
+ @NonNull EditorInfo editorInfo) {
+ if (inputContentInfo == null) {
+ throw new NullPointerException("inputContentInfo");
+ }
+ if (editorInfo == null) {
+ throw new NullPointerException("editorInfo");
+ }
+
+ return mImm.exposeContent(mToken, inputContentInfo, editorInfo);
+ }
+
+ /**
* Performs a dump of the InputMethodService's internal state. Override
* to add your own information to the dump.
*/
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index f4bf3ea..4acb729 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2385,6 +2385,13 @@
public abstract LongCounter getDischargeCoulombCounter();
/**
+ * Returns the estimated real battery capacity, which may be less than the capacity
+ * declared by the PowerProfile.
+ * @return The estimated battery capacity in mAh.
+ */
+ public abstract int getEstimatedBatteryCapacity();
+
+ /**
* Return the array of discharge step durations.
*/
public abstract LevelStepTracker getDischargeLevelStepTracker();
@@ -2836,7 +2843,8 @@
whichBatteryRealtime / 1000, whichBatteryUptime / 1000,
totalRealtime / 1000, totalUptime / 1000,
getStartClockTime(),
- whichBatteryScreenOffRealtime / 1000, whichBatteryScreenOffUptime / 1000);
+ whichBatteryScreenOffRealtime / 1000, whichBatteryScreenOffUptime / 1000,
+ getEstimatedBatteryCapacity());
// Calculate wakelock times across all uids.
@@ -3348,6 +3356,16 @@
final SparseArray<? extends Uid> uidStats = getUidStats();
final int NU = uidStats.size();
+ final int estimatedBatteryCapacity = getEstimatedBatteryCapacity();
+ if (estimatedBatteryCapacity > 0) {
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Estimated battery capacity: ");
+ sb.append(BatteryStatsHelper.makemAh(estimatedBatteryCapacity));
+ sb.append(" mAh");
+ pw.println(sb.toString());
+ }
+
sb.setLength(0);
sb.append(prefix);
sb.append(" Time on battery: ");
diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl
index 082194b..cc2af21 100644
--- a/core/java/android/os/IDeviceIdleController.aidl
+++ b/core/java/android/os/IDeviceIdleController.aidl
@@ -38,8 +38,6 @@
long addPowerSaveTempWhitelistAppForMms(String name, int userId, String reason);
long addPowerSaveTempWhitelistAppForSms(String name, int userId, String reason);
void exitIdle(String reason);
- void downloadServiceActive(IBinder token);
- void downloadServiceInactive();
boolean registerMaintenanceActivityListener(IMaintenanceActivityListener listener);
void unregisterMaintenanceActivityListener(IMaintenanceActivityListener listener);
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 4506f51..f664e70 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -1184,6 +1184,8 @@
/** @hide */
public static final int PROC_QUOTES = 0x400;
/** @hide */
+ public static final int PROC_CHAR = 0x800;
+ /** @hide */
public static final int PROC_OUT_STRING = 0x1000;
/** @hide */
public static final int PROC_OUT_LONG = 0x2000;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 88cf138..e51df0f 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1322,13 +1322,20 @@
/**
* @hide Key with the location in the {@link android.util.MemoryIntArray} where
- * to look up the generation id of the backing table.
+ * to look up the generation id of the backing table. The value is an integer.
*
* @see #CALL_METHOD_TRACK_GENERATION_KEY
*/
public static final String CALL_METHOD_GENERATION_INDEX_KEY = "_generation_index";
/**
+ * @hide Key with the settings table generation. The value is an integer.
+ *
+ * @see #CALL_METHOD_TRACK_GENERATION_KEY
+ */
+ public static final String CALL_METHOD_GENERATION_KEY = "_generation";
+
+ /**
* @hide - User handle argument extra to the fast-path call()-based requests
*/
public static final String CALL_METHOD_USER_KEY = "_user";
@@ -1478,11 +1485,11 @@
private int mCurrentGeneration;
public GenerationTracker(@NonNull MemoryIntArray array, int index,
- Runnable errorHandler) {
+ int generation, Runnable errorHandler) {
mArray = array;
mIndex = index;
mErrorHandler = errorHandler;
- mCurrentGeneration = readCurrentGeneration();
+ mCurrentGeneration = generation;
}
public boolean isGenerationChanged() {
@@ -1638,6 +1645,8 @@
final int index = b.getInt(
CALL_METHOD_GENERATION_INDEX_KEY, -1);
if (array != null && index >= 0) {
+ final int generation = b.getInt(
+ CALL_METHOD_GENERATION_KEY, 0);
if (DEBUG) {
Log.i(TAG, "Received generation tracker for type:"
+ mUri.getPath() + " in package:"
@@ -1645,7 +1654,7 @@
+ userHandle + " with index:" + index);
}
mGenerationTracker = new GenerationTracker(array, index,
- () -> {
+ generation, () -> {
synchronized (this) {
Log.e(TAG, "Error accessing generation"
+ " tracker - removing");
@@ -8498,8 +8507,6 @@
/**
* The name of the device
- *
- * @hide
*/
public static final String DEVICE_NAME = "device_name";
@@ -9065,6 +9072,12 @@
*/
public static final String SYSTEM_NAVIGATION_KEYS_ENABLED =
"system_navigation_keys_enabled";
+
+ /**
+ * Whether cell is enabled/disabled
+ * @hide
+ */
+ public static final String CELL_ON = "cell_on";
}
/**
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index ab9e497..27b0a8b 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -153,6 +153,13 @@
public static final String EXTRA_SELF_CHANGE = "com.android.voicemail.extra.SELF_CHANGE";
/**
+ * Extra included in {@link #ACTION_SYNC_VOICEMAIL} broadcast intents to indicate which {@link
+ * PhoneAccountHandle} to sync.
+ */
+ public static final String EXTRA_PHONE_ACCOUNT_HANDLE =
+ "android.provider.extra.PHONE_ACCOUNT_HANDLE";
+
+ /**
* Name of the source package field, which must be same across all voicemail related tables.
* This is an internal field.
* @hide
@@ -454,6 +461,9 @@
* {@link #CONFIGURATION_STATE_OK},
* {@link #CONFIGURATION_STATE_NOT_CONFIGURED},
* {@link #CONFIGURATION_STATE_CAN_BE_CONFIGURED}
+ * {@link #CONFIGURATION_STATE_CONFIGURING}
+ * {@link #CONFIGURATION_STATE_FAILED}
+ * {@link #CONFIGURATION_STATE_DISABLED}
* <P>Type: INTEGER</P>
*/
public static final String CONFIGURATION_STATE = "configuration_state";
@@ -473,6 +483,21 @@
*/
public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2;
/**
+ * Value of {@link #CONFIGURATION_STATE} to indicate that visual voicemail still is being
+ * configured.
+ */
+ public static final int CONFIGURATION_STATE_CONFIGURING = 3;
+ /**
+ * Value of {@link #CONFIGURATION_STATE} to indicate that visual voicemail has failed to
+ * be configured.
+ */
+ public static final int CONFIGURATION_STATE_FAILED = 4;
+ /**
+ * Value of {@link #CONFIGURATION_STATE} to indicate that visual voicemail is disabled by
+ * the user.
+ */
+ public static final int CONFIGURATION_STATE_DISABLED = 5;
+ /**
* The data channel state of the voicemail source. This the channel through which the source
* pulls voicemail data from a remote server.
*
diff --git a/core/java/android/security/NetworkSecurityPolicy.java b/core/java/android/security/NetworkSecurityPolicy.java
index 331063e..1b1c300 100644
--- a/core/java/android/security/NetworkSecurityPolicy.java
+++ b/core/java/android/security/NetworkSecurityPolicy.java
@@ -17,7 +17,10 @@
package android.security;
import android.annotation.TestApi;
+import android.content.Context;
+import android.content.pm.PackageManager;
import android.security.net.config.ApplicationConfig;
+import android.security.net.config.ManifestConfigSource;
/**
* Network security policy.
@@ -98,4 +101,16 @@
public void handleTrustStorageUpdate() {
ApplicationConfig.getDefaultInstance().handleTrustStorageUpdate();
}
+
+ /**
+ * Returns an {@link ApplicationConfig} based on the configuration for {@code packageName}.
+ *
+ * @hide
+ */
+ public static ApplicationConfig getApplicationConfigForPackage(Context context,
+ String packageName) throws PackageManager.NameNotFoundException {
+ Context appContext = context.createPackageContext(packageName, 0);
+ ManifestConfigSource source = new ManifestConfigSource(appContext);
+ return new ApplicationConfig(source);
+ }
}
diff --git a/core/java/android/service/quicksettings/IQSService.aidl b/core/java/android/service/quicksettings/IQSService.aidl
index 747f185..bf96357 100644
--- a/core/java/android/service/quicksettings/IQSService.aidl
+++ b/core/java/android/service/quicksettings/IQSService.aidl
@@ -23,6 +23,7 @@
* @hide
*/
interface IQSService {
+ Tile getTile(in ComponentName component);
void updateQsTile(in Tile tile);
void updateStatusIcon(in Tile tile, in Icon icon,
String contentDescription);
diff --git a/core/java/android/service/quicksettings/IQSTileService.aidl b/core/java/android/service/quicksettings/IQSTileService.aidl
index bfde8702..b6c830c 100644
--- a/core/java/android/service/quicksettings/IQSTileService.aidl
+++ b/core/java/android/service/quicksettings/IQSTileService.aidl
@@ -15,15 +15,10 @@
*/
package android.service.quicksettings;
-import android.service.quicksettings.Tile;
-import android.service.quicksettings.IQSService;
-
/**
* @hide
*/
oneway interface IQSTileService {
- void setQSService(in IQSService service);
- void setQSTile(in Tile tile);
void onTileAdded();
void onTileRemoved();
void onStartListening();
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index 4e9a075..50411ab 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -118,6 +118,11 @@
/**
* @hide
*/
+ public static final String EXTRA_SERVICE = "service";
+
+ /**
+ * @hide
+ */
public static final String EXTRA_COMPONENT = "android.service.quicksettings.extra.COMPONENT";
private final H mHandler = new H(Looper.getMainLooper());
@@ -305,18 +310,19 @@
@Override
public IBinder onBind(Intent intent) {
+ mService = IQSService.Stub.asInterface(intent.getIBinderExtra(EXTRA_SERVICE));
+ try {
+ ComponentName component = intent.getParcelableExtra(EXTRA_COMPONENT);
+ mTile = mService.getTile(component);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Unable to reach IQSService", e);
+ }
+ if (mTile != null) {
+ mTile.setService(mService);
+ mHandler.sendEmptyMessage(H.MSG_START_SUCCESS);
+ }
return new IQSTileService.Stub() {
@Override
- public void setQSService(IQSService service) throws RemoteException {
- mHandler.obtainMessage(H.MSG_SET_SERVICE, service).sendToTarget();
- }
-
- @Override
- public void setQSTile(Tile tile) throws RemoteException {
- mHandler.obtainMessage(H.MSG_SET_TILE, tile).sendToTarget();
- }
-
- @Override
public void onTileRemoved() throws RemoteException {
mHandler.sendEmptyMessage(H.MSG_TILE_REMOVED);
}
@@ -349,14 +355,13 @@
}
private class H extends Handler {
- private static final int MSG_SET_TILE = 1;
- private static final int MSG_START_LISTENING = 2;
- private static final int MSG_STOP_LISTENING = 3;
- private static final int MSG_TILE_ADDED = 4;
- private static final int MSG_TILE_REMOVED = 5;
- private static final int MSG_TILE_CLICKED = 6;
- private static final int MSG_SET_SERVICE = 7;
- private static final int MSG_UNLOCK_COMPLETE = 8;
+ private static final int MSG_START_LISTENING = 1;
+ private static final int MSG_STOP_LISTENING = 2;
+ private static final int MSG_TILE_ADDED = 3;
+ private static final int MSG_TILE_REMOVED = 4;
+ private static final int MSG_TILE_CLICKED = 5;
+ private static final int MSG_UNLOCK_COMPLETE = 6;
+ private static final int MSG_START_SUCCESS = 7;
public H(Looper looper) {
super(looper);
@@ -365,18 +370,6 @@
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case MSG_SET_SERVICE:
- mService = (IQSService) msg.obj;
- if (mTile != null) {
- mTile.setService(mService);
- }
- break;
- case MSG_SET_TILE:
- mTile = (Tile) msg.obj;
- if (mService != null && mTile != null) {
- mTile.setService(mService);
- }
- break;
case MSG_TILE_ADDED:
TileService.this.onTileAdded();
break;
@@ -408,6 +401,12 @@
mUnlockRunnable.run();
}
break;
+ case MSG_START_SUCCESS:
+ try {
+ mService.onStartSuccessful(mTile);
+ } catch (RemoteException e) {
+ }
+ break;
}
}
}
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index a865307..d3db74d 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -232,6 +232,19 @@
return sThreadInstance.get();
}
+ /** Destroys the calling thread's choreographer
+ * @hide
+ */
+ public static void releaseInstance() {
+ Choreographer old = sThreadInstance.get();
+ sThreadInstance.remove();
+ old.dispose();
+ }
+
+ private void dispose() {
+ mDisplayEventReceiver.dispose();
+ }
+
/**
* The amount of time, in milliseconds, between each frame of the animation.
* <p>
diff --git a/core/java/android/view/DisplayAdjustments.java b/core/java/android/view/DisplayAdjustments.java
index 272740f..dd86062 100644
--- a/core/java/android/view/DisplayAdjustments.java
+++ b/core/java/android/view/DisplayAdjustments.java
@@ -23,8 +23,6 @@
/** @hide */
public class DisplayAdjustments {
- public static final boolean DEVELOPMENT_RESOURCES_DEPEND_ON_ACTIVITY_TOKEN = false;
-
public static final DisplayAdjustments DEFAULT_DISPLAY_ADJUSTMENTS = new DisplayAdjustments();
private volatile CompatibilityInfo mCompatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
@@ -64,7 +62,7 @@
throw new IllegalArgumentException(
"setConfiguration: Cannot modify DEFAULT_DISPLAY_ADJUSTMENTS");
}
- mConfiguration = configuration;
+ mConfiguration = configuration != null ? configuration : Configuration.EMPTY;
}
public Configuration getConfiguration() {
@@ -74,10 +72,8 @@
@Override
public int hashCode() {
int hash = 17;
- hash = hash * 31 + mCompatInfo.hashCode();
- if (DEVELOPMENT_RESOURCES_DEPEND_ON_ACTIVITY_TOKEN) {
- hash = hash * 31 + (mConfiguration == null ? 0 : mConfiguration.hashCode());
- }
+ hash = hash * 31 + Objects.hashCode(mCompatInfo);
+ hash = hash * 31 + Objects.hashCode(mConfiguration);
return hash;
}
diff --git a/core/java/android/view/DragAndDropPermissions.java b/core/java/android/view/DragAndDropPermissions.java
index a3dbdb1..71afaaa 100644
--- a/core/java/android/view/DragAndDropPermissions.java
+++ b/core/java/android/view/DragAndDropPermissions.java
@@ -16,12 +16,14 @@
package android.view;
+import android.app.Activity;
import android.app.ActivityManagerNative;
import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.RemoteException;
-import com.android.internal.view.IDragAndDropPermissions;
-import dalvik.system.CloseGuard;
+import com.android.internal.view.IDragAndDropPermissions;
/**
* {@link DragAndDropPermissions} controls the access permissions for the content URIs associated
@@ -33,20 +35,27 @@
* Which permissions are granted is defined by the set of flags passed to {@link
* View#startDragAndDrop(android.content.ClipData, View.DragShadowBuilder, Object, int)
* View.startDragAndDrop} by the app that started the drag operation.
+ * </p>
* <p>
* The life cycle of the permissions is bound to the activity used to call {@link
* android.app.Activity#requestDragAndDropPermissions(DragEvent) requestDragAndDropPermissions}. The
* permissions are revoked when this activity is destroyed, or when {@link #release()} is called,
* whichever occurs first.
+ * </p>
+ * <p>
+ * If you anticipate that your application will receive a large number of drops (e.g. document
+ * editor), you should try to call {@link #release()} on the obtained permissions as soon as they
+ * are no longer required. Permissions can be added to your activity's
+ * {@link Activity#onSaveInstanceState} bundle and later retrieved in order to manually release
+ * the permissions once they are no longer needed.
+ * </p>
*/
-public final class DragAndDropPermissions {
+public final class DragAndDropPermissions implements Parcelable {
private final IDragAndDropPermissions mDragAndDropPermissions;
private IBinder mPermissionOwnerToken;
- private final CloseGuard mCloseGuard = CloseGuard.get();
-
/**
* Create a new {@link DragAndDropPermissions} object to control the access permissions for
* content URIs associated with {@link DragEvent}.
@@ -79,7 +88,6 @@
} catch (RemoteException e) {
return false;
}
- mCloseGuard.open("release");
return true;
}
@@ -96,7 +104,6 @@
} catch (RemoteException e) {
return false;
}
- mCloseGuard.open("release");
return true;
}
@@ -109,18 +116,34 @@
mPermissionOwnerToken = null;
} catch (RemoteException e) {
}
- mCloseGuard.close();
+ }
+
+ public static final Parcelable.Creator<DragAndDropPermissions> CREATOR =
+ new Parcelable.Creator<DragAndDropPermissions> () {
+ @Override
+ public DragAndDropPermissions createFromParcel(Parcel source) {
+ return new DragAndDropPermissions(source);
+ }
+
+ @Override
+ public DragAndDropPermissions[] newArray(int size) {
+ return new DragAndDropPermissions[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
}
@Override
- protected void finalize() throws Throwable {
- try {
- if (mCloseGuard != null) {
- mCloseGuard.warnIfOpen();
- }
- release();
- } finally {
- super.finalize();
- }
+ public void writeToParcel(Parcel destination, int flags) {
+ destination.writeStrongInterface(mDragAndDropPermissions);
+ destination.writeStrongBinder(mPermissionOwnerToken);
+ }
+
+ private DragAndDropPermissions(Parcel in) {
+ mDragAndDropPermissions = IDragAndDropPermissions.Stub.asInterface(in.readStrongBinder());
+ mPermissionOwnerToken = in.readStrongBinder();
}
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index f8a6a17..72126d0 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -106,12 +106,13 @@
* @param alwaysFocusable True if the app windows are always focusable regardless of the stack
* they are in.
* @param homeTask True if this is the task.
+ * @param targetSdkVersion The application's target SDK version
*/
void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
in Rect taskBounds, in Configuration configuration, int taskResizeMode,
- boolean alwaysFocusable, boolean homeTask);
+ boolean alwaysFocusable, boolean homeTask, int targetSdkVersion);
/**
*
* @param token The token we are adding to the input task Id.
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 599c9c72..990d553 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -796,16 +796,16 @@
public static final int KEYCODE_COPY = 278;
/** Key code constant: Paste key. */
public static final int KEYCODE_PASTE = 279;
- /** Key code constant: fingerprint navigation up */
- public static final int KEYCODE_FP_NAV_UP = 280;
- /** Key code constant: fingerprint navigation down */
- public static final int KEYCODE_FP_NAV_DOWN = 281;
- /** Key code constant: fingerprint navigation left*/
- public static final int KEYCODE_FP_NAV_LEFT = 282;
- /** Key code constant: fingerprint navigation right */
- public static final int KEYCODE_FP_NAV_RIGHT = 283;
+ /** Key code constant: Consumed by the system for navigation up */
+ public static final int KEYCODE_SYSTEM_NAVIGATION_UP = 280;
+ /** Key code constant: Consumed by the system for navigation down */
+ public static final int KEYCODE_SYSTEM_NAVIGATION_DOWN = 281;
+ /** Key code constant: Consumed by the system for navigation left*/
+ public static final int KEYCODE_SYSTEM_NAVIGATION_LEFT = 282;
+ /** Key code constant: Consumed by the system for navigation right */
+ public static final int KEYCODE_SYSTEM_NAVIGATION_RIGHT = 283;
- private static final int LAST_KEYCODE = KEYCODE_FP_NAV_RIGHT;
+ private static final int LAST_KEYCODE = KEYCODE_SYSTEM_NAVIGATION_RIGHT;
// NOTE: If you add a new keycode here you must also add it to:
// isSystem()
@@ -1852,10 +1852,10 @@
case KeyEvent.KEYCODE_BRIGHTNESS_DOWN:
case KeyEvent.KEYCODE_BRIGHTNESS_UP:
case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
- case KeyEvent.KEYCODE_FP_NAV_UP:
- case KeyEvent.KEYCODE_FP_NAV_DOWN:
- case KeyEvent.KEYCODE_FP_NAV_LEFT:
- case KeyEvent.KEYCODE_FP_NAV_RIGHT:
+ case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP:
+ case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN:
+ case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_LEFT:
+ case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_RIGHT:
return true;
}
@@ -2941,11 +2941,13 @@
public static final Parcelable.Creator<KeyEvent> CREATOR
= new Parcelable.Creator<KeyEvent>() {
+ @Override
public KeyEvent createFromParcel(Parcel in) {
in.readInt(); // skip token, we already know this is a KeyEvent
return KeyEvent.createFromParcelBody(in);
}
+ @Override
public KeyEvent[] newArray(int size) {
return new KeyEvent[size];
}
@@ -2969,6 +2971,7 @@
mEventTime = in.readLong();
}
+ @Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(PARCEL_TOKEN_KEY_EVENT);
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 7da849a..286e097 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -58,6 +58,7 @@
private static native long nativeGetNextFrameNumber(long nativeObject);
private static native int nativeSetScalingMode(long nativeObject, int scalingMode);
+ private static native void nativeSetBuffersTransform(long nativeObject, long transform);
public static final Parcelable.Creator<Surface> CREATOR =
new Parcelable.Creator<Surface>() {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 415e70c..f1abca8 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -51,7 +51,7 @@
private static native void nativeSetLayer(long nativeObject, int zorder);
private static native void nativeSetPosition(long nativeObject, float x, float y);
- private static native void nativeSetPositionAppliesWithResize(long nativeObject);
+ private static native void nativeSetGeometryAppliesWithResize(long nativeObject);
private static native void nativeSetSize(long nativeObject, int w, int h);
private static native void nativeSetTransparentRegionHint(long nativeObject, Region region);
private static native void nativeSetAlpha(long nativeObject, float alpha);
@@ -89,6 +89,8 @@
private static native void nativeSetOverrideScalingMode(long nativeObject,
int scalingMode);
private static native IBinder nativeGetHandle(long nativeObject);
+ private static native boolean nativeGetTransformToDisplayInverse(long nativeObject);
+
private static native Display.HdrCapabilities nativeGetHdrCapabilities(IBinder displayToken);
@@ -393,6 +395,10 @@
return nativeGetHandle(mNativeObject);
}
+ public boolean getTransformToDisplayInverse() {
+ return nativeGetTransformToDisplayInverse(mNativeObject);
+ }
+
/** flag the transaction as an animation */
public static void setAnimationTransaction() {
nativeSetAnimationTransaction();
@@ -409,13 +415,15 @@
}
/**
- * If the size changes in this transaction, position updates specified
+ * If the buffer size changes in this transaction, position and crop updates specified
* in this transaction will not complete until a buffer of the new size
- * arrives.
+ * arrives. As transform matrix and size are already frozen in this fashion,
+ * this enables totally freezing the surface until the resize has completed
+ * (at which point the geometry influencing aspects of this transaction will then occur)
*/
- public void setPositionAppliesWithResize() {
+ public void setGeometryAppliesWithResize() {
checkNotReleased();
- nativeSetPositionAppliesWithResize(mNativeObject);
+ nativeSetGeometryAppliesWithResize(mNativeObject);
}
public void setSize(int w, int h) {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index d59c8ac..ac10927 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -124,6 +124,7 @@
int mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
boolean mIsCreating = false;
+ private volatile boolean mRtHandlingPositionUpdates = false;
final Handler mHandler = new Handler() {
@Override
@@ -464,7 +465,8 @@
|| mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {
getLocationInWindow(mLocation);
- if (DEBUG) Log.i(TAG, "Changes: creating=" + creating
+ if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ + "Changes: creating=" + creating
+ " format=" + formatChanged + " size=" + sizeChanged
+ " visible=" + visibleChanged
+ " left=" + (mWindowSpaceLeft != mLocation[0])
@@ -497,7 +499,7 @@
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
;
- if (!creating && !force && !mUpdateWindowNeeded && !sizeChanged) {
+ if (!creating && !force && !sizeChanged) {
mLayout.privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY;
} else {
@@ -534,7 +536,8 @@
mReportDrawNeeded = false;
mDrawingStopped = !visible;
- if (DEBUG) Log.i(TAG, "Cur surface: " + mSurface);
+ if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ + "Cur surface: " + mSurface);
relayoutResult = mSession.relayout(
mWindow, mWindow.mSeq, mLayout, mWindowSpaceWidth, mWindowSpaceHeight,
@@ -547,7 +550,8 @@
reportDrawNeeded = true;
}
- if (DEBUG) Log.i(TAG, "New surface: " + mNewSurface
+ if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ + "New surface: " + mNewSurface
+ ", vis=" + visible + ", frame=" + mWinFrame);
mSurfaceFrame.left = 0;
@@ -581,7 +585,8 @@
if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
mSurfaceCreated = false;
if (mSurface.isValid()) {
- if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceDestroyed");
+ if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ + "visibleChanged -- surfaceDestroyed");
callbacks = getSurfaceCallbacks();
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceDestroyed(mSurfaceHolder);
@@ -594,7 +599,8 @@
if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
mSurfaceCreated = true;
mIsCreating = true;
- if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceCreated");
+ if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ + "visibleChanged -- surfaceCreated");
if (callbacks == null) {
callbacks = getSurfaceCallbacks();
}
@@ -604,7 +610,8 @@
}
if (creating || formatChanged || sizeChanged
|| visibleChanged || realSizeChanged) {
- if (DEBUG) Log.i(TAG, "surfaceChanged -- format=" + mFormat
+ if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ + "surfaceChanged -- format=" + mFormat
+ " w=" + myWidth + " h=" + myHeight);
if (callbacks == null) {
callbacks = getSurfaceCallbacks();
@@ -614,7 +621,8 @@
}
}
if (redrawNeeded) {
- if (DEBUG) Log.i(TAG, "surfaceRedrawNeeded");
+ if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ + "surfaceRedrawNeeded");
if (callbacks == null) {
callbacks = getSurfaceCallbacks();
}
@@ -629,7 +637,8 @@
} finally {
mIsCreating = false;
if (redrawNeeded) {
- if (DEBUG) Log.i(TAG, "finishedDrawing");
+ if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ + "finishedDrawing");
mSession.finishDrawing(mWindow);
}
mSession.performDeferredDestroy(mWindow);
@@ -641,7 +650,9 @@
TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
" w=" + mLayout.width + " h=" + mLayout.height +
", frame=" + mSurfaceFrame);
- } else if (!isHardwareAccelerated()) {
+ } else {
+ // Calculate the window position in case RT loses the window
+ // and we need to fallback to a UI-thread driven position update
getLocationInWindow(mLocation);
final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
|| mWindowSpaceTop != mLocation[1];
@@ -662,14 +673,17 @@
mTranslator.translateRectInAppWindowToScreen(mWinFrame);
}
- try {
- Log.d(TAG, String.format("updateWindowPosition UI, " +
- "postion = [%d, %d, %d, %d]", mWinFrame.left, mWinFrame.top,
- mWinFrame.right, mWinFrame.bottom));
- mSession.repositionChild(mWindow, mWinFrame.left, mWinFrame.top,
- mWinFrame.right, mWinFrame.bottom, -1, mWinFrame);
- } catch (RemoteException ex) {
- Log.e(TAG, "Exception from relayout", ex);
+ if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
+ try {
+ if (DEBUG) Log.d(TAG, String.format("%d updateWindowPosition UI, " +
+ "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
+ mWinFrame.left, mWinFrame.top,
+ mWinFrame.right, mWinFrame.bottom));
+ mSession.repositionChild(mWindow, mWinFrame.left, mWinFrame.top,
+ mWinFrame.right, mWinFrame.bottom, -1, mWinFrame);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Exception from relayout", ex);
+ }
}
}
}
@@ -689,6 +703,15 @@
// Guess we got detached, that sucks
return;
}
+ // TODO: This is teensy bit racey in that a brand new SurfaceView moving on
+ // its 2nd frame if RenderThread is running slowly could potentially see
+ // this as false, enter the branch, get pre-empted, then this comes along
+ // and reports a new position, then the UI thread resumes and reports
+ // its position. This could therefore be de-sync'd in that interval, but
+ // the synchronization would violate the rule that RT must never block
+ // on the UI thread which would open up potential deadlocks. The risk of
+ // a single-frame desync is therefore preferable for now.
+ mRtHandlingPositionUpdates = true;
if (mRTLastReportedPosition.left == left
&& mRTLastReportedPosition.top == top
&& mRTLastReportedPosition.right == right
@@ -697,9 +720,9 @@
}
try {
if (DEBUG) {
- Log.d(TAG, String.format("updateWindowPosition RT, frameNr = %d, " +
- "postion = [%d, %d, %d, %d]", frameNumber, left, top,
- right, bottom));
+ Log.d(TAG, String.format("%d updateWindowPosition RT, frameNr = %d, " +
+ "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
+ frameNumber, left, top, right, bottom));
}
// Just using mRTLastReportedPosition as a dummy rect here
session.repositionChild(window, left, top, right, bottom,
@@ -712,6 +735,38 @@
}
}
+ /**
+ * Called by native on RenderThread to notify that the window is no longer in the
+ * draw tree
+ * @hide
+ */
+ public final void windowPositionLostRT(long frameNumber) {
+ if (DEBUG) {
+ Log.d(TAG, String.format("%d windowPositionLostRT RT, frameNr = %d",
+ System.identityHashCode(this), frameNumber));
+ }
+ if (mRtHandlingPositionUpdates) {
+ mRtHandlingPositionUpdates = false;
+ // This callback will happen while the UI thread is blocked, so we can
+ // safely access other member variables at this time.
+ // So do what the UI thread would have done if RT wasn't handling position
+ // updates.
+ if (!mWinFrame.isEmpty() && !mWinFrame.equals(mRTLastReportedPosition)) {
+ try {
+ if (DEBUG) Log.d(TAG, String.format("%d updateWindowPosition, " +
+ "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
+ mWinFrame.left, mWinFrame.top,
+ mWinFrame.right, mWinFrame.bottom));
+ mSession.repositionChild(mWindow, mWinFrame.left, mWinFrame.top,
+ mWinFrame.right, mWinFrame.bottom, frameNumber, mWinFrame);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Exception from relayout", ex);
+ }
+ }
+ mRTLastReportedPosition.setEmpty();
+ }
+ }
+
private SurfaceHolder.Callback[] getSurfaceCallbacks() {
SurfaceHolder.Callback callbacks[];
synchronized (mCallbacks) {
@@ -750,8 +805,7 @@
boolean alwaysConsumeNavBar) {
SurfaceView surfaceView = mSurfaceView.get();
if (surfaceView != null) {
- if (DEBUG) Log.v(
- "SurfaceView", surfaceView + " got resized: w=" + frame.width()
+ if (DEBUG) Log.v(TAG, surfaceView + " got resized: w=" + frame.width()
+ " h=" + frame.height() + ", cur w=" + mCurWidth + " h=" + mCurHeight);
surfaceView.mSurfaceLock.lock();
try {
@@ -907,7 +961,7 @@
private final Canvas internalLockCanvas(Rect dirty) {
mSurfaceLock.lock();
- if (DEBUG) Log.i(TAG, "Locking canvas... stopped="
+ if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
+ mDrawingStopped + ", win=" + mWindow);
Canvas c = null;
@@ -919,7 +973,7 @@
}
}
- if (DEBUG) Log.i(TAG, "Returned canvas: " + c);
+ if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Returned canvas: " + c);
if (c != null) {
mLastLockTime = SystemClock.uptimeMillis();
return c;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 5f6ee09..d4ac300 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -20527,8 +20527,17 @@
* to the target Views. For example, it can contain flags that differentiate between a
* a copy operation and a move operation.
* </p>
- * @param flags Flags that control the drag and drop operation. No flags are currently defined,
- * so the parameter should be set to 0.
+ * @param flags Flags that control the drag and drop operation. This can be set to 0 for no
+ * flags, or any combination of the following:
+ * <ul>
+ * <li>{@link #DRAG_FLAG_GLOBAL}</li>
+ * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li>
+ * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li>
+ * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li>
+ * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li>
+ * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li>
+ * <li>{@link #DRAG_FLAG_OPAQUE}</li>
+ * </ul>
* @return {@code true} if the method completes successfully, or
* {@code false} if it fails anywhere. Returning {@code false} means the system was unable to
* do a drag, and so no drag operation is in progress.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 65f0caa..c427522 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -26,7 +26,9 @@
import android.Manifest;
import android.animation.LayoutTransition;
+import android.annotation.NonNull;
import android.app.ActivityManagerNative;
+import android.app.ResourcesManager;
import android.content.ClipDescription;
import android.content.ComponentCallbacks;
import android.content.Context;
@@ -164,7 +166,7 @@
final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList<>();
final Context mContext;
final IWindowSession mWindowSession;
- final Display mDisplay;
+ @NonNull Display mDisplay;
final DisplayManager mDisplayManager;
final String mBasePackageName;
@@ -308,8 +310,6 @@
boolean mAdded;
boolean mAddedTouchMode;
- final DisplayAdjustments mDisplayAdjustments;
-
// These are accessed by multiple threads.
final Rect mWinFrame; // frame given by window manager.
@@ -413,9 +413,6 @@
mWindowSession = WindowManagerGlobal.getWindowSession();
mDisplay = display;
mBasePackageName = context.getBasePackageName();
-
- mDisplayAdjustments = display.getDisplayAdjustments();
-
mThread = Thread.currentThread();
mLocation = new WindowLeaked(null);
mLocation.fillInStackTrace();
@@ -589,7 +586,8 @@
attrs.setSurfaceInsets(view, false /*manual*/, true /*preservePrevious*/);
}
- CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
+ CompatibilityInfo compatibilityInfo =
+ mDisplay.getDisplayAdjustments().getCompatibilityInfo();
mTranslator = compatibilityInfo.getTranslator();
// If the application owns the surface, don't enable hardware acceleration
@@ -1476,7 +1474,8 @@
surfaceChanged = true;
params = lp;
}
- CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
+ CompatibilityInfo compatibilityInfo =
+ mDisplay.getDisplayAdjustments().getCompatibilityInfo();
if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
params = lp;
mFullRedrawNeeded = true;
@@ -1732,7 +1731,7 @@
}
boolean hwInitialized = false;
- boolean contentInsetsChanged = false;
+ boolean framesChanged = false;
boolean hadSurface = mSurface.isValid();
try {
@@ -1772,7 +1771,7 @@
final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals(
mAttachInfo.mOverscanInsets);
- contentInsetsChanged = !mPendingContentInsets.equals(
+ boolean contentInsetsChanged = !mPendingContentInsets.equals(
mAttachInfo.mContentInsets);
final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
mAttachInfo.mVisibleInsets);
@@ -1822,6 +1821,19 @@
+ mAttachInfo.mVisibleInsets);
}
+ // If any of the insets changed, do a forceLayout on the view so that the
+ // measure cache is cleared. We might have a pending MSG_RESIZED_REPORT
+ // that is supposed to take care of it, but since pending insets are
+ // already modified here, it won't detect the frame change after this.
+ framesChanged = overscanInsetsChanged
+ || contentInsetsChanged
+ || stableInsetsChanged
+ || visibleInsetsChanged
+ || outsetsChanged;
+ if (mAdded && mView != null && framesChanged) {
+ forceLayout(mView);
+ }
+
if (!hadSurface) {
if (mSurface.isValid()) {
// If we are creating a new surface, then we need to
@@ -2005,7 +2017,7 @@
boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
(relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
- || mHeight != host.getMeasuredHeight() || contentInsetsChanged ||
+ || mHeight != host.getMeasuredHeight() || framesChanged ||
updatedConfiguration) {
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
@@ -2014,7 +2026,7 @@
+ mWidth + " measuredWidth=" + host.getMeasuredWidth()
+ " mHeight=" + mHeight
+ " measuredHeight=" + host.getMeasuredHeight()
- + " coveredInsetsChanged=" + contentInsetsChanged);
+ + " framesChanged=" + framesChanged);
// Ask host how big it wants to be
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
@@ -3301,7 +3313,7 @@
+ mWindowAttributes.getTitle()
+ ": " + config);
- CompatibilityInfo ci = mDisplayAdjustments.getCompatibilityInfo();
+ CompatibilityInfo ci = mDisplay.getDisplayAdjustments().getCompatibilityInfo();
if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
config = new Configuration(config);
ci.applyToConfiguration(mNoncompatDensity, config);
@@ -3316,8 +3328,13 @@
// At this point the resources have been updated to
// have the most recent config, whatever that is. Use
// the one in them which may be newer.
- config = mView.getResources().getConfiguration();
+ final Resources localResources = mView.getResources();
+ config = localResources.getConfiguration();
if (force || mLastConfiguration.diff(config) != 0) {
+ // Update the display with new DisplayAdjustments.
+ mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(
+ mDisplay.getDisplayId(), localResources.getDisplayAdjustments());
+
final int lastLayoutDirection = mLastConfiguration.getLayoutDirection();
final int currentLayoutDirection = config.getLayoutDirection();
mLastConfiguration.setTo(config);
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index f8c7d68..dd4e096 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -55,26 +55,26 @@
*/
public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
- private final Display mDisplay;
+ private final Context mContext;
private final Window mParentWindow;
private IBinder mDefaultToken;
- public WindowManagerImpl(Display display) {
- this(display, null);
+ public WindowManagerImpl(Context context) {
+ this(context, null);
}
- private WindowManagerImpl(Display display, Window parentWindow) {
- mDisplay = display;
+ private WindowManagerImpl(Context context, Window parentWindow) {
+ mContext = context;
mParentWindow = parentWindow;
}
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
- return new WindowManagerImpl(mDisplay, parentWindow);
+ return new WindowManagerImpl(mContext, parentWindow);
}
- public WindowManagerImpl createPresentationWindowManager(Display display) {
- return new WindowManagerImpl(display, mParentWindow);
+ public WindowManagerImpl createPresentationWindowManager(Context displayContext) {
+ return new WindowManagerImpl(displayContext, mParentWindow);
}
/**
@@ -90,7 +90,7 @@
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
- mGlobal.addView(view, params, mDisplay, mParentWindow);
+ mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
@Override
@@ -144,6 +144,6 @@
@Override
public Display getDefaultDisplay() {
- return mDisplay;
+ return mContext.getDisplay();
}
}
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index e6f5b83..a8afaf2 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -1410,4 +1410,6 @@
* Called when the configuration has changed, and it's safe to load new values from resources.
*/
public void onConfigurationChanged();
+
+ public boolean shouldRotateSeamlessly(int oldRotation, int newRotation);
}
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 7c3fc8b..0ebbf7f 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -855,5 +855,5 @@
/**
* The default implementation does nothing.
*/
- public boolean insertContent(InputContentInfo inputContentInfo, Bundle opts) { return false; }
+ public boolean commitContent(InputContentInfo inputContentInfo, Bundle opts) { return false; }
}
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index 7ed0d27..2dca892 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -368,10 +368,10 @@
/**
* List of acceptable MIME types for
- * {@link InputConnection#insertContent(InputContentInfo, Bundle)}.
+ * {@link InputConnection#commitContent(InputContentInfo, Bundle)}.
*
* <p>{@code null} or an empty array means that
- * {@link InputConnection#insertContent(InputContentInfo, Bundle)} is not supported in this
+ * {@link InputConnection#commitContent(InputContentInfo, Bundle)} is not supported in this
* editor.</p>
*/
@Nullable
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 05e0569..f7f3694 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -840,7 +840,7 @@
public void closeConnection();
/**
- * Called by the input method to insert a content such as PNG image to the editor.
+ * Called by the input method to commit a content such as PNG image to the editor.
*
* <p>In order to avoid variety of compatibility issues, this focuses on a simple use case,
* where we expect editors and IMEs work cooperatively as follows:</p>
@@ -866,5 +866,5 @@
* @return {@code true} if this request is accepted by the application, no matter if the request
* is already handled or still being handled in background.
*/
- public boolean insertContent(@NonNull InputContentInfo inputContentInfo, @Nullable Bundle opts);
+ public boolean commitContent(@NonNull InputContentInfo inputContentInfo, @Nullable Bundle opts);
}
diff --git a/core/java/android/view/inputmethod/InputConnectionInspector.java b/core/java/android/view/inputmethod/InputConnectionInspector.java
index fb24fcd..727e9ca 100644
--- a/core/java/android/view/inputmethod/InputConnectionInspector.java
+++ b/core/java/android/view/inputmethod/InputConnectionInspector.java
@@ -43,7 +43,7 @@
MissingMethodFlags.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS,
MissingMethodFlags.GET_HANDLER,
MissingMethodFlags.CLOSE_CONNECTION,
- MissingMethodFlags.INSERT_CONTENT,
+ MissingMethodFlags.COMMIT_CONTENT,
})
public @interface MissingMethodFlags {
/**
@@ -82,10 +82,10 @@
*/
int CLOSE_CONNECTION = 1 << 6;
/**
- * {@link InputConnection#insertContent(InputContentInfo, Bundle)} is available in
+ * {@link InputConnection#commitContent(InputContentInfo, Bundle)} is available in
* {@link android.os.Build.VERSION_CODES#N} MR-1 and later.
*/
- int INSERT_CONTENT = 1 << 7;
+ int COMMIT_CONTENT = 1 << 7;
}
private static final Map<Class, Integer> sMissingMethodsMap = Collections.synchronizedMap(
@@ -135,8 +135,8 @@
if (!hasCloseConnection(clazz)) {
flags |= MissingMethodFlags.CLOSE_CONNECTION;
}
- if (!hasInsertContent(clazz)) {
- flags |= MissingMethodFlags.INSERT_CONTENT;
+ if (!hasCommitContent(clazz)) {
+ flags |= MissingMethodFlags.COMMIT_CONTENT;
}
sMissingMethodsMap.put(clazz, flags);
return flags;
@@ -206,9 +206,9 @@
}
}
- private static boolean hasInsertContent(@NonNull final Class clazz) {
+ private static boolean hasCommitContent(@NonNull final Class clazz) {
try {
- final Method method = clazz.getMethod("insertContent", InputContentInfo.class,
+ final Method method = clazz.getMethod("commitContent", InputContentInfo.class,
Bundle.class);
return !Modifier.isAbstract(method.getModifiers());
} catch (NoSuchMethodException e) {
@@ -263,11 +263,11 @@
}
sb.append("closeConnection()");
}
- if ((flags & MissingMethodFlags.INSERT_CONTENT) != 0) {
+ if ((flags & MissingMethodFlags.COMMIT_CONTENT) != 0) {
if (!isEmpty) {
sb.append(",");
}
- sb.append("InsertContent(InputContentInfo, Bundle)");
+ sb.append("commitContent(InputContentInfo, Bundle)");
}
return sb.toString();
}
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index 431836a..af9bcae 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -274,7 +274,7 @@
* {@inheritDoc}
* @throws NullPointerException if the target is {@code null}.
*/
- public boolean insertContent(InputContentInfo inputContentInfo, Bundle opts) {
- return mTarget.insertContent(inputContentInfo, opts);
+ public boolean commitContent(InputContentInfo inputContentInfo, Bundle opts) {
+ return mTarget.commitContent(inputContentInfo, opts);
}
}
diff --git a/core/java/android/view/inputmethod/InputContentInfo.java b/core/java/android/view/inputmethod/InputContentInfo.java
index e2ecfae..9579bbf 100644
--- a/core/java/android/view/inputmethod/InputContentInfo.java
+++ b/core/java/android/view/inputmethod/InputContentInfo.java
@@ -22,13 +22,16 @@
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.RemoteException;
+
+import com.android.internal.inputmethod.IInputContentUriToken;
import java.security.InvalidParameterException;
/**
* A container object with which input methods can send content files to the target application.
*/
-public class InputContentInfo implements Parcelable {
+public final class InputContentInfo implements Parcelable {
@NonNull
private final Uri mContentUri;
@@ -36,6 +39,8 @@
private final ClipDescription mDescription;
@Nullable
private final Uri mLinkUri;
+ @NonNull
+ private IInputContentUriToken mUriToken;
/**
* Constructs {@link InputContentInfo} object only with mandatory data.
@@ -110,7 +115,7 @@
return false;
}
final String contentUriScheme = contentUri.getScheme();
- if (contentUriScheme == null || !contentUriScheme.equalsIgnoreCase("content")) {
+ if (!"content".equals(contentUriScheme)) {
if (throwException) {
throw new InvalidParameterException("contentUri must have content scheme");
}
@@ -137,8 +142,9 @@
public Uri getContentUri() { return mContentUri; }
/**
- * @return {@link ClipDescription} object that contains the metadata of {@code contentUri} such
- * as MIME type(s). {@link ClipDescription#getLabel()} can be used for accessibility purpose.
+ * @return {@link ClipDescription} object that contains the metadata of {@code #getContentUri()}
+ * such as MIME type(s). {@link ClipDescription#getLabel()} can be used for accessibility
+ * purpose.
*/
@NonNull
public ClipDescription getDescription() { return mDescription; }
@@ -149,6 +155,47 @@
@Nullable
public Uri getLinkUri() { return mLinkUri; }
+ void setUriToken(IInputContentUriToken token) {
+ if (mUriToken != null) {
+ throw new IllegalStateException("URI token is already set");
+ }
+ mUriToken = token;
+ }
+
+ /**
+ * Requests a temporary read-only access permission for content URI associated with this object.
+ *
+ * <p>Does nothing if the temporary permission is already granted.</p>
+ */
+ public void requestPermission() {
+ if (mUriToken == null) {
+ return;
+ }
+ try {
+ mUriToken.take();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Releases a temporary read-only access permission for content URI associated with this object.
+ *
+ * <p>Does nothing if the temporary permission is not granted.</p>
+ */
+ public void releasePermission() {
+ if (mUriToken == null) {
+ return;
+ }
+ try {
+ mUriToken.release();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ } finally {
+ mUriToken = null;
+ }
+ }
+
/**
* Used to package this object into a {@link Parcel}.
*
@@ -160,12 +207,23 @@
Uri.writeToParcel(dest, mContentUri);
mDescription.writeToParcel(dest, flags);
Uri.writeToParcel(dest, mLinkUri);
+ if (mUriToken != null) {
+ dest.writeInt(1);
+ dest.writeStrongBinder(mUriToken.asBinder());
+ } else {
+ dest.writeInt(0);
+ }
}
private InputContentInfo(@NonNull Parcel source) {
mContentUri = Uri.CREATOR.createFromParcel(source);
mDescription = ClipDescription.CREATOR.createFromParcel(source);
mLinkUri = Uri.CREATOR.createFromParcel(source);
+ if (source.readInt() == 1) {
+ mUriToken = IInputContentUriToken.Stub.asInterface(source.readStrongBinder());
+ } else {
+ mUriToken = null;
+ }
}
/**
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 4013b30..b35f5c3 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -16,6 +16,7 @@
package android.view.inputmethod;
+import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.os.SomeArgs;
import com.android.internal.view.IInputConnectionWrapper;
import com.android.internal.view.IInputContext;
@@ -30,6 +31,7 @@
import android.annotation.RequiresPermission;
import android.content.Context;
import android.graphics.Rect;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -56,6 +58,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -2288,6 +2291,41 @@
}
}
+ /**
+ * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access
+ * permission to the content.
+ *
+ * <p>See {@link android.inputmethodservice.InputMethodService#exposeContent(InputContentInfo, EditorInfo)}
+ * for details.</p>
+ *
+ * @param token Supplies the identifying token given to an input method when it was started,
+ * which allows it to perform this operation on itself.
+ * @param inputContentInfo Content to be temporarily exposed from the input method to the
+ * application.
+ * This cannot be {@code null}.
+ * @param editorInfo The editor that receives {@link InputContentInfo}.
+ * @return {@code false} if we cannot allow a temporary access permission.
+ * @hide
+ */
+ public boolean exposeContent(@NonNull IBinder token, @NonNull InputContentInfo inputContentInfo,
+ @NonNull EditorInfo editorInfo) {
+ final IInputContentUriToken uriToken;
+ final Uri contentUri = inputContentInfo.getContentUri();
+ try {
+ uriToken = mService.createInputContentUriToken(token, contentUri,
+ editorInfo.packageName);
+ if (uriToken == null) {
+ return false;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "createInputContentAccessToken failed. contentUri=" + contentUri.toString()
+ + " packageName=" + editorInfo.packageName, e);
+ return false;
+ }
+ inputContentInfo.setUriToken(uriToken);
+ return true;
+ }
+
void doDump(FileDescriptor fd, PrintWriter fout, String[] args) {
final Printer p = new PrintWriterPrinter(fout);
p.println("Input method client state for " + this + ":");
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 2d1e0bd..15eb8de 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -141,17 +141,38 @@
*/
public static int loadWebViewNativeLibraryFromPackage(String packageName,
ClassLoader clazzLoader) {
- int ret = waitForProviderAndSetPackageInfo();
- if (ret != LIBLOAD_SUCCESS && ret != LIBLOAD_FAILED_WAITING_FOR_RELRO) {
- return ret;
+ WebViewProviderResponse response = null;
+ try {
+ response = getUpdateService().waitForAndGetProvider();
+ } catch (RemoteException e) {
+ Log.e(LOGTAG, "error waiting for relro creation", e);
+ return LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN;
}
- if (!sPackageInfo.packageName.equals(packageName))
+
+
+ if (response.status != LIBLOAD_SUCCESS
+ && response.status != LIBLOAD_FAILED_WAITING_FOR_RELRO) {
+ return response.status;
+ }
+ if (!response.packageInfo.packageName.equals(packageName)) {
return LIBLOAD_WRONG_PACKAGE_NAME;
+ }
+
+ PackageManager packageManager = AppGlobals.getInitialApplication().getPackageManager();
+ PackageInfo packageInfo;
+ try {
+ packageInfo = packageManager.getPackageInfo(packageName,
+ PackageManager.GET_META_DATA | PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(LOGTAG, "Couldn't find package " + packageName);
+ return LIBLOAD_WRONG_PACKAGE_NAME;
+ }
+ sPackageInfo = packageInfo;
int loadNativeRet = loadNativeLibrary(clazzLoader);
// If we failed waiting for relro we want to return that fact even if we successfully load
// the relro file.
- if (loadNativeRet == LIBLOAD_SUCCESS) return ret;
+ if (loadNativeRet == LIBLOAD_SUCCESS) return response.status;
return loadNativeRet;
}
@@ -288,7 +309,7 @@
Context webViewContext = initialApplication.createApplicationContext(
newPackageInfo.applicationInfo,
Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
- sPackageInfo = response.packageInfo;
+ sPackageInfo = newPackageInfo;
return webViewContext;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
@@ -599,22 +620,6 @@
}
}
- private static int waitForProviderAndSetPackageInfo() {
- WebViewProviderResponse response = null;
- try {
- response =
- getUpdateService().waitForAndGetProvider();
- if (response.status == LIBLOAD_SUCCESS
- || response.status == LIBLOAD_FAILED_WAITING_FOR_RELRO) {
- sPackageInfo = response.packageInfo;
- }
- } catch (RemoteException e) {
- Log.e(LOGTAG, "error waiting for relro creation", e);
- return LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN;
- }
- return response.status;
- }
-
// Assumes that we have waited for relro creation and set sPackageInfo
private static int loadNativeLibrary(ClassLoader clazzLoader) {
if (!sAddressSpaceReserved) {
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index fb532e2..f296421 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -19,7 +19,6 @@
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.NonNull;
-import android.content.ClipData;
import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
@@ -5986,8 +5985,8 @@
}
@Override
- public boolean insertContent(InputContentInfo inputContentInfo, Bundle opts) {
- return getTarget().insertContent(inputContentInfo, opts);
+ public boolean commitContent(InputContentInfo inputContentInfo, Bundle opts) {
+ return getTarget().commitContent(inputContentInfo, opts);
}
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 3f6e625..6477f07 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1001,9 +1001,13 @@
}
/**
- * Returns the popup's height MeasureSpec.
+ * Returns the popup's requested height. May be a layout constant such as
+ * {@link LayoutParams#WRAP_CONTENT} or {@link LayoutParams#MATCH_PARENT}.
+ * <p>
+ * The actual size of the popup may depend on other factors such as
+ * clipping and window layout.
*
- * @return the height MeasureSpec of the popup
+ * @return the popup height in pixels or a layout constant
* @see #setHeight(int)
*/
public int getHeight() {
@@ -1011,12 +1015,16 @@
}
/**
- * Sets the popup's height MeasureSpec.
+ * Sets the popup's requested height. May be a layout constant such as
+ * {@link LayoutParams#WRAP_CONTENT} or {@link LayoutParams#MATCH_PARENT}.
+ * <p>
+ * The actual size of the popup may depend on other factors such as
+ * clipping and window layout.
* <p>
* If the popup is showing, calling this method will take effect the next
* time the popup is shown.
*
- * @param height the height MeasureSpec of the popup
+ * @param height the popup height in pixels or a layout constant
* @see #getHeight()
* @see #isShowing()
*/
@@ -1025,9 +1033,13 @@
}
/**
- * Returns the popup's width MeasureSpec.
+ * Returns the popup's requested width. May be a layout constant such as
+ * {@link LayoutParams#WRAP_CONTENT} or {@link LayoutParams#MATCH_PARENT}.
+ * <p>
+ * The actual size of the popup may depend on other factors such as
+ * clipping and window layout.
*
- * @return the width MeasureSpec of the popup
+ * @return the popup width in pixels or a layout constant
* @see #setWidth(int)
*/
public int getWidth() {
@@ -1035,12 +1047,16 @@
}
/**
- * Sets the popup's width MeasureSpec.
+ * Sets the popup's requested width. May be a layout constant such as
+ * {@link LayoutParams#WRAP_CONTENT} or {@link LayoutParams#MATCH_PARENT}.
+ * <p>
+ * The actual size of the popup may depend on other factors such as
+ * clipping and window layout.
* <p>
* If the popup is showing, calling this method will take effect the next
* time the popup is shown.
*
- * @param width the width MeasureSpec of the popup
+ * @param width the popup width in pixels or a layout constant
* @see #getWidth()
* @see #isShowing()
*/
@@ -1377,6 +1393,14 @@
}
}
+ private int computeGravity() {
+ int gravity = Gravity.START | Gravity.TOP;
+ if (mClipToScreen || mClippingEnabled) {
+ gravity |= Gravity.DISPLAY_CLIP_VERTICAL | Gravity.DISPLAY_CLIP_HORIZONTAL;
+ }
+ return gravity;
+ }
+
/**
* <p>Generate the layout parameters for the popup window.</p>
*
@@ -1391,7 +1415,7 @@
// screen. The view is then positioned to the appropriate location by
// setting the x and y offsets to match the anchor's bottom-left
// corner.
- p.gravity = Gravity.START | Gravity.TOP;
+ p.gravity = computeGravity();
p.flags = computeFlags(p.flags);
p.type = mWindowLayoutType;
p.token = token;
@@ -1517,13 +1541,9 @@
anchor.getWindowVisibleDisplayFrame(displayFrame);
if (width == MATCH_PARENT) {
width = displayFrame.right - displayFrame.left;
- } else if (width == WRAP_CONTENT) {
- width = mContentView.getMeasuredWidth();
}
if (height == MATCH_PARENT) {
height = displayFrame.bottom - displayFrame.top;
- } else if (height == WRAP_CONTENT) {
- height = mContentView.getMeasuredHeight();
}
// Let the window manager know to align the top to y.
@@ -1946,6 +1966,12 @@
update = true;
}
+ final int newGravity = computeGravity();
+ if (newGravity != p.gravity) {
+ p.gravity = newGravity;
+ update = true;
+ }
+
if (update) {
setLayoutDirectionFromAnchor();
mWindowManager.updateViewLayout(mDecorView, p);
@@ -1958,8 +1984,8 @@
* Calling this function also updates the window with the current popup
* state as described for {@link #update()}.
*
- * @param width the new width, must be >= 0 or -1 to ignore
- * @param height the new height, must be >= 0 or -1 to ignore
+ * @param width the new width in pixels, must be >= 0 or -1 to ignore
+ * @param height the new height in pixels, must be >= 0 or -1 to ignore
*/
public void update(int width, int height) {
final WindowManager.LayoutParams p =
@@ -1976,8 +2002,8 @@
*
* @param x the new x location
* @param y the new y location
- * @param width the new width, must be >= 0 or -1 to ignore
- * @param height the new height, must be >= 0 or -1 to ignore
+ * @param width the new width in pixels, must be >= 0 or -1 to ignore
+ * @param height the new height in pixels, must be >= 0 or -1 to ignore
*/
public void update(int x, int y, int width, int height) {
update(x, y, width, height, false);
@@ -1992,8 +2018,8 @@
*
* @param x the new x location
* @param y the new y location
- * @param width the new width, must be >= 0 or -1 to ignore
- * @param height the new height, must be >= 0 or -1 to ignore
+ * @param width the new width in pixels, must be >= 0 or -1 to ignore
+ * @param height the new height in pixels, must be >= 0 or -1 to ignore
* @param force {@code true} to reposition the window even if the specified
* position already seems to correspond to the LayoutParams,
* {@code false} to only reposition if needed
@@ -2052,6 +2078,12 @@
update = true;
}
+ final int newGravity = computeGravity();
+ if (newGravity != p.gravity) {
+ p.gravity = newGravity;
+ update = true;
+ }
+
int newAccessibilityIdOfAnchor =
(mAnchor != null) ? mAnchor.get().getAccessibilityViewId() : -1;
if (newAccessibilityIdOfAnchor != p.accessibilityIdOfAnchor) {
@@ -2072,8 +2104,8 @@
* state as described for {@link #update()}.
*
* @param anchor the popup's anchor view
- * @param width the new width, must be >= 0 or -1 to ignore
- * @param height the new height, must be >= 0 or -1 to ignore
+ * @param width the new width in pixels, must be >= 0 or -1 to ignore
+ * @param height the new height in pixels, must be >= 0 or -1 to ignore
*/
public void update(View anchor, int width, int height) {
update(anchor, false, 0, 0, width, height);
@@ -2092,8 +2124,8 @@
* @param anchor the popup's anchor view
* @param xoff x offset from the view's left edge
* @param yoff y offset from the view's bottom edge
- * @param width the new width, must be >= 0 or -1 to ignore
- * @param height the new height, must be >= 0 or -1 to ignore
+ * @param width the new width in pixels, must be >= 0 or -1 to ignore
+ * @param height the new height in pixels, must be >= 0 or -1 to ignore
*/
public void update(View anchor, int xoff, int yoff, int width, int height) {
update(anchor, true, xoff, yoff, width, height);
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 9cdb73a..0988c92 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -161,7 +161,7 @@
private int mTitleMarginTop;
private int mTitleMarginBottom;
- private final RtlSpacingHelper mContentInsets = new RtlSpacingHelper();
+ private RtlSpacingHelper mContentInsets;
private int mContentInsetStartWithNavigation;
private int mContentInsetEndWithActions;
@@ -270,6 +270,7 @@
final int contentInsetRight =
a.getDimensionPixelSize(R.styleable.Toolbar_contentInsetRight, 0);
+ ensureContentInsets();
mContentInsets.setAbsolute(contentInsetLeft, contentInsetRight);
if (contentInsetStart != RtlSpacingHelper.UNDEFINED ||
@@ -463,13 +464,13 @@
*/
public void setTitleMarginBottom(int margin) {
mTitleMarginBottom = margin;
-
requestLayout();
}
@Override
public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) {
super.onRtlPropertiesChanged(layoutDirection);
+ ensureContentInsets();
mContentInsets.setDirection(layoutDirection == LAYOUT_DIRECTION_RTL);
}
@@ -1092,6 +1093,7 @@
* @attr ref android.R.styleable#Toolbar_contentInsetStart
*/
public void setContentInsetsRelative(int contentInsetStart, int contentInsetEnd) {
+ ensureContentInsets();
mContentInsets.setRelative(contentInsetStart, contentInsetEnd);
}
@@ -1112,7 +1114,7 @@
* @attr ref android.R.styleable#Toolbar_contentInsetStart
*/
public int getContentInsetStart() {
- return mContentInsets.getStart();
+ return mContentInsets != null ? mContentInsets.getStart() : 0;
}
/**
@@ -1132,7 +1134,7 @@
* @attr ref android.R.styleable#Toolbar_contentInsetEnd
*/
public int getContentInsetEnd() {
- return mContentInsets.getEnd();
+ return mContentInsets != null ? mContentInsets.getEnd() : 0;
}
/**
@@ -1154,6 +1156,7 @@
* @attr ref android.R.styleable#Toolbar_contentInsetRight
*/
public void setContentInsetsAbsolute(int contentInsetLeft, int contentInsetRight) {
+ ensureContentInsets();
mContentInsets.setAbsolute(contentInsetLeft, contentInsetRight);
}
@@ -1174,7 +1177,7 @@
* @attr ref android.R.styleable#Toolbar_contentInsetLeft
*/
public int getContentInsetLeft() {
- return mContentInsets.getLeft();
+ return mContentInsets != null ? mContentInsets.getLeft() : 0;
}
/**
@@ -1194,7 +1197,7 @@
* @attr ref android.R.styleable#Toolbar_contentInsetRight
*/
public int getContentInsetRight() {
- return mContentInsets.getRight();
+ return mContentInsets != null ? mContentInsets.getRight() : 0;
}
/**
@@ -2128,6 +2131,12 @@
}
}
+ private void ensureContentInsets() {
+ if (mContentInsets == null) {
+ mContentInsets = new RtlSpacingHelper();
+ }
+ }
+
/**
* Accessor to enable LayoutLib to get ActionMenuPresenter directly.
*/
diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java
index e3fce51..e782c3c 100644
--- a/core/java/com/android/internal/app/LocaleStore.java
+++ b/core/java/com/android/internal/app/LocaleStore.java
@@ -307,6 +307,9 @@
localizedLocales.add(li.getLangScriptKey());
}
+ // Serbian in Latin script is only partially localized in N.
+ localizedLocales.remove("sr-Latn");
+
for (LocaleInfo li : sLocaleCache.values()) {
li.setTranslated(localizedLocales.contains(li.getLangScriptKey()));
}
diff --git a/core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl b/core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl
new file mode 100644
index 0000000..8abc807
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl
@@ -0,0 +1,27 @@
+/*
+** 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.
+*/
+
+package com.android.internal.inputmethod;
+
+import android.os.IBinder;
+
+/**
+ * {@hide}
+ */
+interface IInputContentUriToken {
+ void take();
+ void release();
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 07d38d7..a1df8c1 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -108,7 +108,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 146 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 147 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -547,6 +547,8 @@
private int mLoadedNumConnectivityChange;
private int mUnpluggedNumConnectivityChange;
+ private int mEstimatedBatteryCapacity = -1;
+
private final NetworkStats.Entry mTmpNetworkStatsEntry = new NetworkStats.Entry();
private PowerProfile mPowerProfile;
@@ -578,6 +580,11 @@
return mDischargeCounter;
}
+ @Override
+ public int getEstimatedBatteryCapacity() {
+ return mEstimatedBatteryCapacity;
+ }
+
public BatteryStatsImpl() {
this(new SystemClocks());
}
@@ -7625,6 +7632,11 @@
numSpeedSteps);
firstCpuOfCluster += mPowerProfile.getNumCoresInCpuCluster(i);
}
+
+ if (mEstimatedBatteryCapacity == -1) {
+ // Initialize the estimated battery capacity to a known preset one.
+ mEstimatedBatteryCapacity = (int) mPowerProfile.getBatteryCapacity();
+ }
}
}
@@ -8174,6 +8186,12 @@
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i].reset(false);
}
+
+ if (mPowerProfile != null) {
+ mEstimatedBatteryCapacity = (int) mPowerProfile.getBatteryCapacity();
+ } else {
+ mEstimatedBatteryCapacity = -1;
+ }
mInteractiveTimer.reset(false);
mPowerSaveModeEnabledTimer.reset(false);
mLastIdleTimeStart = elapsedRealtimeMillis;
@@ -9158,7 +9176,7 @@
}
void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime, final boolean onBattery,
- final int oldStatus, final int level) {
+ final int oldStatus, final int level, final int chargeUAh) {
boolean doWrite = false;
Message m = mHandler.obtainMessage(MSG_REPORT_POWER_CHANGE);
m.arg1 = onBattery ? 1 : 0;
@@ -9212,6 +9230,10 @@
}
doWrite = true;
resetAllStatsLocked();
+ if (chargeUAh > 0) {
+ // Only use the reported coulomb charge value if it is supported and reported.
+ mEstimatedBatteryCapacity = (int) ((level / 100.0) * (chargeUAh / 1000));
+ }
mDischargeStartLevel = level;
reset = true;
mDischargeStepTracker.init();
@@ -9379,7 +9401,7 @@
mDischargeScreenOffCounter.addCountLocked(chargeDiff);
}
mHistoryCur.batteryChargeUAh = chargeUAh;
- setOnBatteryLocked(elapsedRealtime, uptime, onBattery, oldStatus, level);
+ setOnBatteryLocked(elapsedRealtime, uptime, onBattery, oldStatus, level, chargeUAh);
} else {
boolean changed = false;
if (mHistoryCur.batteryLevel != level) {
@@ -10093,6 +10115,7 @@
mDischargePlugLevel = in.readInt();
mDischargeCurrentLevel = in.readInt();
mCurrentBatteryLevel = in.readInt();
+ mEstimatedBatteryCapacity = in.readInt();
mLowDischargeAmountSinceCharge = in.readInt();
mHighDischargeAmountSinceCharge = in.readInt();
mDischargeAmountScreenOnSinceCharge = in.readInt();
@@ -10445,6 +10468,7 @@
out.writeInt(mDischargePlugLevel);
out.writeInt(mDischargeCurrentLevel);
out.writeInt(mCurrentBatteryLevel);
+ out.writeInt(mEstimatedBatteryCapacity);
out.writeInt(getLowDischargeAmountSinceCharge());
out.writeInt(getHighDischargeAmountSinceCharge());
out.writeInt(getDischargeAmountScreenOnSinceCharge());
@@ -10809,6 +10833,7 @@
mRealtime = in.readLong();
mRealtimeStart = in.readLong();
mOnBattery = in.readInt() != 0;
+ mEstimatedBatteryCapacity = in.readInt();
mOnBatteryInternal = false; // we are no longer really running.
mOnBatteryTimeBase.readFromParcel(in);
mOnBatteryScreenOffTimeBase.readFromParcel(in);
@@ -10992,6 +11017,7 @@
out.writeLong(mRealtime);
out.writeLong(mRealtimeStart);
out.writeInt(mOnBattery ? 1 : 0);
+ out.writeInt(mEstimatedBatteryCapacity);
mOnBatteryTimeBase.writeToParcel(out, uSecUptime, uSecRealtime);
mOnBatteryScreenOffTimeBase.writeToParcel(out, uSecUptime, uSecRealtime);
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 9c960c0..73a3a0b 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -753,7 +753,7 @@
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
- } catch (RuntimeException ex) {
+ } catch (Throwable ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
index 8addffb0..0ab3a41 100644
--- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java
+++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
@@ -217,6 +217,7 @@
synchronized (this) {
// Make sure no more messages are being sent.
mChoreographer = null;
+ Choreographer.releaseInstance();
}
}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 7706ff7..20f10b3 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -112,4 +112,5 @@
void addQsTile(in ComponentName tile);
void remQsTile(in ComponentName tile);
void clickQsTile(in ComponentName tile);
+ void handleSystemNavigationKey(in int key);
}
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 3d05422..698e387 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -66,4 +66,5 @@
void addTile(in ComponentName tile);
void remTile(in ComponentName tile);
void clickTile(in ComponentName tile);
+ void handleSystemNavigationKey(in int key);
}
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index fc189a3..dce9d2c 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -62,7 +62,7 @@
private static final int DO_CLEAR_META_KEY_STATES = 130;
private static final int DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO = 140;
private static final int DO_CLOSE_CONNECTION = 150;
- private static final int DO_INSERT_CONTENT = 160;
+ private static final int DO_COMMIT_CONTENT = 160;
@GuardedBy("mLock")
@Nullable
@@ -243,9 +243,9 @@
dispatchMessage(obtainMessage(DO_CLOSE_CONNECTION));
}
- public void insertContent(InputContentInfo inputContentInfo, Bundle opts,
+ public void commitContent(InputContentInfo inputContentInfo, Bundle opts,
int seq, IInputContextCallback callback) {
- dispatchMessage(obtainMessageOOSC(DO_INSERT_CONTENT, inputContentInfo, opts, seq, callback));
+ dispatchMessage(obtainMessageOOSC(DO_COMMIT_CONTENT, inputContentInfo, opts, seq, callback));
}
void dispatchMessage(Message msg) {
@@ -559,26 +559,26 @@
}
return;
}
- case DO_INSERT_CONTENT: {
+ case DO_COMMIT_CONTENT: {
SomeArgs args = (SomeArgs) msg.obj;
try {
InputConnection ic = getInputConnection();
if (ic == null || !isActive()) {
- Log.w(TAG, "insertContent on inactive InputConnection");
- args.callback.setInsertContentResult(false, args.seq);
+ Log.w(TAG, "commitContent on inactive InputConnection");
+ args.callback.setCommitContentResult(false, args.seq);
return;
}
final InputContentInfo inputContentInfo = (InputContentInfo) args.arg1;
if (inputContentInfo == null || !inputContentInfo.validate()) {
- Log.w(TAG, "insertContent with invalid inputContentInfo="
+ Log.w(TAG, "commitContent with invalid inputContentInfo="
+ inputContentInfo);
- args.callback.setInsertContentResult(false, args.seq);
+ args.callback.setCommitContentResult(false, args.seq);
return;
}
- args.callback.setInsertContentResult(
- ic.insertContent(inputContentInfo, (Bundle) args.arg2), args.seq);
+ args.callback.setCommitContentResult(
+ ic.commitContent(inputContentInfo, (Bundle) args.arg2), args.seq);
} catch (RemoteException e) {
- Log.w(TAG, "Got RemoteException calling insertContent", e);
+ Log.w(TAG, "Got RemoteException calling commitContent", e);
}
return;
}
diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl
index bd47355..0d5c8a1 100644
--- a/core/java/com/android/internal/view/IInputContext.aidl
+++ b/core/java/com/android/internal/view/IInputContext.aidl
@@ -78,6 +78,6 @@
void requestUpdateCursorAnchorInfo(int cursorUpdateMode, int seq,
IInputContextCallback callback);
- void insertContent(in InputContentInfo inputContentInfo, in Bundle opts, int sec,
+ void commitContent(in InputContentInfo inputContentInfo, in Bundle opts, int sec,
IInputContextCallback callback);
}
diff --git a/core/java/com/android/internal/view/IInputContextCallback.aidl b/core/java/com/android/internal/view/IInputContextCallback.aidl
index 933cdc0..0f40a83 100644
--- a/core/java/com/android/internal/view/IInputContextCallback.aidl
+++ b/core/java/com/android/internal/view/IInputContextCallback.aidl
@@ -28,5 +28,5 @@
void setExtractedText(in ExtractedText extractedText, int seq);
void setSelectedText(CharSequence selectedText, int seq);
void setRequestUpdateCursorAnchorInfoResult(boolean result, int seq);
- void setInsertContentResult(boolean result, int seq);
+ void setCommitContentResult(boolean result, int seq);
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index cb7c3bf..9e4b43b 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -16,11 +16,13 @@
package com.android.internal.view;
+import android.net.Uri;
import android.os.ResultReceiver;
import android.text.style.SuggestionSpan;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
import android.view.inputmethod.EditorInfo;
+import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.view.InputBindResult;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
@@ -81,5 +83,8 @@
int getInputMethodWindowVisibleHeight();
void clearLastInputMethodWindowForTransition(in IBinder token);
+ IInputContentUriToken createInputContentUriToken(in IBinder token, in Uri contentUri,
+ in String packageName);
+
oneway void notifyUserAction(int sequenceNumber);
}
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index 6d4d45c..5e78ec5 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -16,7 +16,6 @@
package com.android.internal.view;
-import android.content.ClipData;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
@@ -48,7 +47,7 @@
public ExtractedText mExtractedText;
public int mCursorCapsMode;
public boolean mRequestUpdateCursorAnchorInfoResult;
- public boolean mInsertContentResult;
+ public boolean mCommitContentResult;
// A 'pool' of one InputContextCallback. Each ICW request will attempt to gain
// exclusive access to this object.
@@ -175,15 +174,15 @@
}
}
- public void setInsertContentResult(boolean result, int seq) {
+ public void setCommitContentResult(boolean result, int seq) {
synchronized (this) {
if (seq == mSeq) {
- mInsertContentResult = result;
+ mCommitContentResult = result;
mHaveValue = true;
notifyAll();
} else {
Log.i(TAG, "Got out-of-sequence callback " + seq + " (expected " + mSeq
- + ") in setInsertContentResult, ignoring.");
+ + ") in setCommitContentResult, ignoring.");
}
}
}
@@ -507,19 +506,19 @@
// Nothing should happen when called from input method.
}
- public boolean insertContent(InputContentInfo inputContentInfo, Bundle opts) {
+ public boolean commitContent(InputContentInfo inputContentInfo, Bundle opts) {
boolean result = false;
- if (isMethodMissing(MissingMethodFlags.INSERT_CONTENT)) {
+ if (isMethodMissing(MissingMethodFlags.COMMIT_CONTENT)) {
// This method is not implemented.
return false;
}
try {
InputContextCallback callback = InputContextCallback.getInstance();
- mIInputContext.insertContent(inputContentInfo, opts, callback.mSeq, callback);
+ mIInputContext.commitContent(inputContentInfo, opts, callback.mSeq, callback);
synchronized (callback) {
callback.waitForResultLocked();
if (callback.mHaveValue) {
- result = callback.mInsertContentResult;
+ result = callback.mCommitContentResult;
}
}
callback.dispose();
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index f4237d2..50f23bf 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -30,7 +30,6 @@
#include <utils/Looper.h>
#include <utils/Vector.h>
-#include <endian.h> // htobe64
#include <map>
namespace {
@@ -200,19 +199,9 @@
env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
}
- // java.util.UUID constructor UUID(long a, long b) assumes the two long inputs a and b
- // correspond to first half and second half of the 16-byte stream in big-endian,
- // respectively, if the byte stream is serialized according to RFC 4122 (Sec. 4.1.2).
- //
- // For Java UUID 12345678-90AB-CDEF-1122-334455667788, the byte stream will be
- // (uint8_t) {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, ....} according RFC 4122.
- //
- // According to Java UUID constructor document, the long parameter a should be always
- // 0x12345678980ABCDEF regardless of host machine endianess. Thus, htobe64 is used to
- // convert int64_t read directly, which will be in host-endian, to the big-endian required
- // by Java constructor.
- const int64_t (&uuid)[2] = nativeSensor.getUuid().i64;
- env->CallVoidMethod(sensor, sensorOffsets.setUuid, htobe64(uuid[0]), htobe64(uuid[1]));
+ // TODO(b/29547335): Rename "setUuid" method to "setId".
+ int64_t id = nativeSensor.getId();
+ env->CallVoidMethod(sensor, sensorOffsets.setUuid, id, 0);
}
return sensor;
}
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index f7a5e8a..3d952b0 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -832,6 +832,7 @@
PROC_COMBINE = 0x100,
PROC_PARENS = 0x200,
PROC_QUOTES = 0x400,
+ PROC_CHAR = 0x800,
PROC_OUT_STRING = 0x1000,
PROC_OUT_LONG = 0x2000,
PROC_OUT_FLOAT = 0x4000,
@@ -933,8 +934,13 @@
floatsData[di] = strtof(buffer+start, &end);
}
if ((mode&PROC_OUT_LONG) != 0 && di < NL) {
- char* end;
- longsData[di] = strtoll(buffer+start, &end, 10);
+ if ((mode&PROC_CHAR) != 0) {
+ // Caller wants single first character returned as one long.
+ longsData[di] = buffer[start];
+ } else {
+ char* end;
+ longsData[di] = strtoll(buffer+start, &end, 10);
+ }
}
if ((mode&PROC_OUT_STRING) != 0 && di < NS) {
jstring str = env->NewStringUTF(buffer+start);
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index f9936ae..a0d5904 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -81,14 +81,12 @@
NativeDisplayEventReceiver::~NativeDisplayEventReceiver() {
JNIEnv* env = AndroidRuntime::getJNIEnv();
env->DeleteGlobalRef(mReceiverWeakGlobal);
+ ALOGV("receiver %p ~ dtor display event receiver.", this);
}
void NativeDisplayEventReceiver::dispose() {
ALOGV("receiver %p ~ Disposing display event receiver.", this);
-
- if (!mReceiver.initCheck()) {
- mMessageQueue->getLooper()->removeFd(mReceiver.getFd());
- }
+ DisplayEventDispatcher::dispose();
}
void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count) {
@@ -143,7 +141,7 @@
}
static void nativeDispose(JNIEnv* env, jclass clazz, jlong receiverPtr) {
- sp<NativeDisplayEventReceiver> receiver =
+ NativeDisplayEventReceiver* receiver =
reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
receiver->dispose();
receiver->decStrong(gDisplayEventReceiverClassInfo.clazz); // drop reference held by the object
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index a6db0f4..4fc546c 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -534,6 +534,7 @@
// ----------------------------------------------------------------------------
jmethodID gSurfaceViewPositionUpdateMethod;
+jmethodID gSurfaceViewPositionLostMethod;
static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,
jlong renderNodePtr, jobject surfaceview) {
@@ -581,6 +582,20 @@
info.canvasContext.enqueueFrameWork(std::move(functor));
}
+ virtual void onPositionLost(RenderNode& node, const TreeInfo* info) override {
+ if (CC_UNLIKELY(!mWeakRef || (info && !info->updateWindowPositions))) return;
+
+ if (info) {
+ auto functor = std::bind(
+ std::mem_fn(&SurfaceViewPositionUpdater::doNotifyPositionLost), this,
+ (jlong) info->canvasContext.getFrameNumber());
+
+ info->canvasContext.enqueueFrameWork(std::move(functor));
+ } else {
+ doNotifyPositionLost(0);
+ }
+ }
+
private:
JNIEnv* jnienv() {
JNIEnv* env;
@@ -607,6 +622,21 @@
env->DeleteLocalRef(localref);
}
+ void doNotifyPositionLost(jlong frameNumber) {
+ ATRACE_NAME("SurfaceView position lost");
+
+ JNIEnv* env = jnienv();
+ jobject localref = env->NewLocalRef(mWeakRef);
+ if (CC_UNLIKELY(!localref)) {
+ jnienv()->DeleteWeakGlobalRef(mWeakRef);
+ mWeakRef = nullptr;
+ return;
+ }
+
+ env->CallVoidMethod(localref, gSurfaceViewPositionLostMethod, frameNumber);
+ env->DeleteLocalRef(localref);
+ }
+
JavaVM* mVm;
jobject mWeakRef;
};
@@ -701,6 +731,8 @@
jclass clazz = FindClassOrDie(env, "android/view/SurfaceView");
gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz,
"updateWindowPositionRT", "(JIIII)V");
+ gSurfaceViewPositionLostMethod = GetMethodIDOrDie(env, clazz,
+ "windowPositionLostRT", "(J)V");
clazz = FindClassOrDie(env, "android/view/RenderNode");
gOnRenderNodeDetached = GetMethodIDOrDie(env, clazz,
"onRenderNodeDetached", "()V");
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index ff75677..fa1313b 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -248,10 +248,10 @@
}
}
-static void nativeSetPositionAppliesWithResize(JNIEnv* env, jclass clazz,
+static void nativeSetGeometryAppliesWithResize(JNIEnv* env, jclass clazz,
jlong nativeObject) {
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
- status_t err = ctrl->setPositionAppliesWithResize();
+ status_t err = ctrl->setGeometryAppliesWithResize();
if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
@@ -626,6 +626,16 @@
return javaObjectForIBinder(env, ctrl->getHandle());
}
+static jboolean nativeGetTransformToDisplayInverse(JNIEnv* env, jclass clazz, jlong nativeObject) {
+ bool out = false;
+ auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ status_t status = ctrl->getTransformToDisplayInverse(&out);
+ if (status != NO_ERROR) {
+ return false;
+ }
+ return out;
+}
+
static jobject nativeGetHdrCapabilities(JNIEnv* env, jclass clazz, jobject tokenObject) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObject));
if (token == NULL) return NULL;
@@ -667,8 +677,8 @@
(void*)nativeSetLayer },
{"nativeSetPosition", "(JFF)V",
(void*)nativeSetPosition },
- {"nativeSetPositionAppliesWithResize", "(J)V",
- (void*)nativeSetPositionAppliesWithResize },
+ {"nativeSetGeometryAppliesWithResize", "(J)V",
+ (void*)nativeSetGeometryAppliesWithResize },
{"nativeSetSize", "(JII)V",
(void*)nativeSetSize },
{"nativeSetTransparentRegionHint", "(JLandroid/graphics/Region;)V",
@@ -722,7 +732,9 @@
{"nativeSetOverrideScalingMode", "(JI)V",
(void*)nativeSetOverrideScalingMode },
{"nativeGetHandle", "(J)Landroid/os/IBinder;",
- (void*)nativeGetHandle }
+ (void*)nativeGetHandle },
+ {"nativeGetTransformToDisplayInverse", "(J)Z",
+ (void*)nativeGetTransformToDisplayInverse },
};
int register_android_view_SurfaceControl(JNIEnv* env)
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 212bf57..61a0bda 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -255,7 +255,6 @@
void runVectorDrawableAnimators(AnimationContext* context) {
for (auto it = mVectorDrawableAnimators.begin(); it != mVectorDrawableAnimators.end();) {
- (*it)->pushStaging(*context);
if ((*it)->animate(*context)) {
it = mVectorDrawableAnimators.erase(it);
} else {
@@ -264,6 +263,12 @@
}
}
+ void pushStagingVectorDrawableAnimators(AnimationContext* context) {
+ for (auto& anim : mVectorDrawableAnimators) {
+ anim->pushStaging(*context);
+ }
+ }
+
void destroy() {
for (auto& renderNode : mPendingAnimatingRenderNodes) {
renderNode->animators().endAllStagingAnimators();
@@ -328,6 +333,9 @@
// already ran in each RenderNode. Note that these animators don't damage the RenderNodes.
// The damaging is done in prepareTree as needed after checking whether a VD has been
// modified.
+ if (mode == TreeInfo::MODE_FULL) {
+ mRootNode->pushStagingVectorDrawableAnimators(this);
+ }
mRootNode->runVectorDrawableAnimators(this);
}
diff --git a/core/res/res/layout/immersive_mode_cling.xml b/core/res/res/layout/immersive_mode_cling.xml
index 28fbea5..b08b0f4 100644
--- a/core/res/res/layout/immersive_mode_cling.xml
+++ b/core/res/res/layout/immersive_mode_cling.xml
@@ -16,7 +16,7 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="#ff009688"
+ android:background="?android:attr/colorAccent"
android:gravity="center_vertical"
android:paddingBottom="24dp">
@@ -47,7 +47,7 @@
android:paddingTop="8dp"
android:scaleType="center"
android:src="@drawable/ic_expand_more_48dp"
- android:tint="#ff009688"/>
+ android:tint="?android:attr/colorAccent"/>
</FrameLayout>
<TextView
diff --git a/core/res/res/layout/unsupported_display_size_dialog_content.xml b/core/res/res/layout/unsupported_display_size_dialog_content.xml
new file mode 100644
index 0000000..5e5cf00
--- /dev/null
+++ b/core/res/res/layout/unsupported_display_size_dialog_content.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="?attr/dialogPreferredPadding"
+ android:paddingLeft="?attr/dialogPreferredPadding"
+ android:paddingRight="?attr/dialogPreferredPadding">
+
+ <CheckBox
+ android:id="@+id/ask_checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:text="@string/unsupported_display_size_show" />
+</FrameLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index a4a7e4e..299737f 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skaal"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Wys altyd"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Heraktiveer hierdie in Stelselinstellings > Programme > Afgelaai."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> steun nie die huidige skermgrootte-instelling nie en sal dalk onverwags reageer."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Wys altyd"</string>
<string name="smv_application" msgid="3307209192155442829">"Die program <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) het sy selfopgelegde StrictMode-beleid oortree."</string>
<string name="smv_process" msgid="5120397012047462446">"Die proses <xliff:g id="PROCESS">%1$s</xliff:g> het die selfopgelegde StrictMode-beleid geskend."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android gradeer tans op..."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index e6875da..8949db5 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"የልኬት ለውጥ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"ሁልጊዜ አሳይ"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"በስርዓት ቅንብሮች ውስጥ ይሄንን ዳግም አንቃ> Apps &gt፤ወርዷል፡፡"</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> አሁን ያለውን የማሳያ መጠን ቅንብር አይደግፍም እና ያልተጠብቀ ባሕሪ ሊያሳይ ይችላል።"</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"ሁልጊዜ አሳይ"</string>
<string name="smv_application" msgid="3307209192155442829">"መተግበሪያው <xliff:g id="APPLICATION">%1$s</xliff:g>( ሂደት<xliff:g id="PROCESS">%2$s</xliff:g>) በራስ ተነሳሺ StrictMode ደንብን ይተላለፋል።"</string>
<string name="smv_process" msgid="5120397012047462446">"ሂደቱ <xliff:g id="PROCESS">%1$s</xliff:g> በራስ ተነሳሺ StrictMode ፖሊሲን ይተላለፋል።"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android እያሻሻለ ነው..."</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index b5e59f3..8b5b698 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1107,6 +1107,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"تدرج"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"الإظهار دائمًا"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"يمكنك إعادة تمكين هذا في إعدادات النظام > التطبيقات > ما تم تنزيله."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> غير متوافق مع الإعداد الحالي لحجم شاشة العرض وربما يعمل بطريقة غير متوقعة."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"العرض دائمًا"</string>
<string name="smv_application" msgid="3307209192155442829">"انتهك التطبيق <xliff:g id="APPLICATION">%1$s</xliff:g> (العملية <xliff:g id="PROCESS">%2$s</xliff:g>) سياسة StrictMode المفروضة ذاتيًا."</string>
<string name="smv_process" msgid="5120397012047462446">"انتهكت العملية <xliff:g id="PROCESS">%1$s</xliff:g> سياسة StrictMode المفروضة ذاتيًا."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"جارٍ ترقية Android..."</string>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 4076415..d9b000d3 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Miqyas"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Həmişə göstər"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Bunları Sistem ayarlarında yenidən aktivləşdir Yüklənmiş > Tətbiqlər >."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> cari Ekran ölçüsü ayarını dəstəkləmir və gözlənilməz şəkildə davrana bilər."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Həmişə göstərin"</string>
<string name="smv_application" msgid="3307209192155442829">"Tətbiq <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) StrictMode siyasətini pozdu."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> prosesi StrictMode siyasətini pozdu."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android təkmilləşdirilir..."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index da70645..7bb4ffb 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Мащаб"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Винаги да се показва"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Активирайте отново това в „Системни настройки“ > „Приложения“ > „Изтеглени“."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддържа текущата настройка за размер на дисплея и може да се държи по неочакван начин."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Винаги да се показва"</string>
<string name="smv_application" msgid="3307209192155442829">"Приложението „<xliff:g id="APPLICATION">%1$s</xliff:g>“ (процес „<xliff:g id="PROCESS">%2$s</xliff:g>“) наруши правилото за стриктен режим, наложено от самото него."</string>
<string name="smv_process" msgid="5120397012047462446">"Процесът <xliff:g id="PROCESS">%1$s</xliff:g> наруши правилото за стриктен режим, наложено от самия него."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android се надстройва..."</string>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index 3f26a49..3ed2018 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"স্কেল"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"সবসময় দেখান"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"সিস্টেম সেটিংস> অ্যাপ্স> ডাউনলোড করাগুলি এ এটি পুনঃসক্ষম করুন৷"</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g>, বর্তমান প্রদর্শনের আকারের সেটিংস সমর্থন করে না এবং অপ্রত্যাশিত আচরণ করতে পারে৷"</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"সর্বদা দেখান"</string>
<string name="smv_application" msgid="3307209192155442829">"অ্যাপ্লিকেশানটি <xliff:g id="APPLICATION">%1$s</xliff:g> (প্রক্রিয়া <xliff:g id="PROCESS">%2$s</xliff:g>) তার স্ব-প্রয়োগ করা কঠোর মোড নীতি লঙ্ঘন করেছে৷"</string>
<string name="smv_process" msgid="5120397012047462446">"প্রক্রিয়াটি <xliff:g id="PROCESS">%1$s</xliff:g> তার স্ব-প্রয়োগ করা কঠোর মোড নীতি লঙ্ঘন করেছে৷"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android আপগ্রেড করা হচ্ছে..."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 458e810..bcfb6c2 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostra sempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Torna a activar-ho a Configuració del sistema > Aplicacions > Baixades."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet la mida de pantalla actual i és possible que funcioni de manera inesperada."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostra sempre"</string>
<string name="smv_application" msgid="3307209192155442829">"L\'aplicació <xliff:g id="APPLICATION">%1$s</xliff:g>(procés <xliff:g id="PROCESS">%2$s</xliff:g>) ha incomplert la seva política autoimposada de mode estricte."</string>
<string name="smv_process" msgid="5120397012047462446">"El procés <xliff:g id="PROCESS">%1$s</xliff:g> ha incomplert la seva política de mode estricte."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android s\'està actualitzant..."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 214f234d13..7dab4f6 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1061,6 +1061,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Měřítko"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Vždy zobrazovat"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Tento režim znovu povolíte v sekci Nastavení systému > Aplikace > Stažené."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> aktuální nastavení velikosti zobrazení nepodporuje a může se chovat neočekávaně."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Vždy zobrazovat"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikace <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) porušila své vlastní vynucené zásady StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> porušil své vlastní vynucené zásady StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android se upgraduje..."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 59447c3..d505f18 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skaler"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Vis altid"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktivér dette igen i Systemindstillinger > Apps > Downloadet."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> understøtter ikke den aktuelle indstilling for visningsstørrelse og vil muligvis ikke fungere som forventet."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Vis altid"</string>
<string name="smv_application" msgid="3307209192155442829">"Appen <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) har overtrådt sin egen StrictMode-politik."</string>
<string name="smv_process" msgid="5120397012047462446">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> har overtrådt sin egen StrictMode-politik."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android opgraderes..."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 79a2dba..2dc10a6a 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skalieren"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Immer anzeigen"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Eine erneute Aktivierung ist in den Systemeinstellungen unter \"Apps > Heruntergeladen\" möglich."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> unterstützt nicht die aktuelle Einstellung für die Anzeigegröße, sodass ein unerwartetes Verhalten auftreten kann."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Immer anzeigen"</string>
<string name="smv_application" msgid="3307209192155442829">"Die App <xliff:g id="APPLICATION">%1$s</xliff:g> (Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) hat gegen deine selbsterzwungene StrictMode-Richtlinie verstoßen."</string>
<string name="smv_process" msgid="5120397012047462446">"Der Prozess <xliff:g id="PROCESS">%1$s</xliff:g> hat gegen seine selbsterzwungene StrictMode-Richtlinie verstoßen."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android wird aktualisiert..."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 4b388f8..b02fabe 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Κλίμακα"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Να εμφανίζονται πάντα"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Ενεργοποιήστε το ξανά στις Ρυθμίσεις συστημάτων > Εφαρμογές > Ληφθείσες."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> δεν υποστηρίζει την τρέχουσα ρύθμιση Μεγέθους οθόνης και ενδέχεται να παρουσιάζει μη αναμενόμενη συμπεριφορά."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Να εμφανίζεται πάντα"</string>
<string name="smv_application" msgid="3307209192155442829">"Η εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> (διεργασία <xliff:g id="PROCESS">%2$s</xliff:g>) παραβίασε την αυτοεπιβαλλόμενη πολιτική StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Η διεργασία <xliff:g id="PROCESS">%1$s</xliff:g> παραβίασε την αυτοεπιβαλόμενη πολιτική StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Το Android αναβαθμίζεται..."</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 12c5e22..a40f0f3 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scale"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Always show"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Re-enable this in System settings > Apps > Downloaded."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Always show"</string>
<string name="smv_application" msgid="3307209192155442829">"The app <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has violated its self-enforced Strict Mode policy."</string>
<string name="smv_process" msgid="5120397012047462446">"The process <xliff:g id="PROCESS">%1$s</xliff:g> has violated its self-enforced StrictMode policy."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android is upgrading…"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 12c5e22..a40f0f3 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scale"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Always show"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Re-enable this in System settings > Apps > Downloaded."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Always show"</string>
<string name="smv_application" msgid="3307209192155442829">"The app <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has violated its self-enforced Strict Mode policy."</string>
<string name="smv_process" msgid="5120397012047462446">"The process <xliff:g id="PROCESS">%1$s</xliff:g> has violated its self-enforced StrictMode policy."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android is upgrading…"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 12c5e22..a40f0f3 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scale"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Always show"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Re-enable this in System settings > Apps > Downloaded."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Always show"</string>
<string name="smv_application" msgid="3307209192155442829">"The app <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has violated its self-enforced Strict Mode policy."</string>
<string name="smv_process" msgid="5120397012047462446">"The process <xliff:g id="PROCESS">%1$s</xliff:g> has violated its self-enforced StrictMode policy."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android is upgrading…"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index c66a659..8396060 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar siempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Volver a activar Configuración del sistema > Aplicaciones > Descargas"</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> no es compatible con la configuración del tamaño de pantalla actual. Es posible que no se comporte de manera correcta."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar siempre"</string>
<string name="smv_application" msgid="3307209192155442829">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) ha infringido su política StrictMode de aplicación automática."</string>
<string name="smv_process" msgid="5120397012047462446">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> ha violado su política StrictMode autoimpuesta."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android se está actualizando..."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index ae916ca..384bfb7 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar siempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Para volver a habilitar esta opción, accede a Ajustes > Aplicaciones > Descargadas."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admite el tamaño de pantalla actual y es posible que funcione de forma inesperada."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar siempre"</string>
<string name="smv_application" msgid="3307209192155442829">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) ha infringido su política StrictMode autoaplicable."</string>
<string name="smv_process" msgid="5120397012047462446">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> ha infringido su política StrictMode autoaplicable."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Actualizando Android"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 15c9d83..3cf1a57 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Mõõtkava"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Kuva alati"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Lubage see uuesti valikutes Süsteemiseaded > Rakendused > Allalaaditud."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> ei toeta praegust ekraani suuruse seadet ja võib ootamatult käituda."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Kuva alati"</string>
<string name="smv_application" msgid="3307209192155442829">"Rakendus <xliff:g id="APPLICATION">%1$s</xliff:g> (protsess <xliff:g id="PROCESS">%2$s</xliff:g>) on rikkunud isekehtestatud StrictMode\'i eeskirju."</string>
<string name="smv_process" msgid="5120397012047462446">"Protsess <xliff:g id="PROCESS">%1$s</xliff:g> on rikkunud isejõustatud StrictMode\'i eeskirju."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android viiakse üle uuemale versioonile ..."</string>
diff --git a/core/res/res/values-eu-rES-watch/styles_material.xml b/core/res/res/values-eu-rES-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-eu-rES-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?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.
+ -->
+
+<!--
+===============================================================
+ 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 styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index bf6c2de..b6404ea 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Eskala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Erakutsi beti"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Gaitu hori berriro Sistemaren ezarpenak > Aplikazioak > Deskargatutakoak."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak ez du onartzen uneko pantailaren tamaina eta espero ez bezala joka lezake."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Erakutsi beti"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioak (<xliff:g id="PROCESS">%2$s</xliff:g> prozesua) berak aplikatutako StrictMode gidalerroa urratu du."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> prozesuak bere kabuz ezarritako StrictMode gidalerroak urratu ditu."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android bertsio-berritzen ari da…"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 52fa6b2..27ba6d1 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"مقیاس"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"همیشه نشان داده شود"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"در تنظیمات سیستم >برنامهها > مورد بارگیری شده آن را دوباره فعال کنید."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> از تنظیم فعلی اندازه نمایشگر پشتیبانی نمیکند و ممکن است رفتار غیرمنتظرهای داشته باشد."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"همیشه نشان داده شود"</string>
<string name="smv_application" msgid="3307209192155442829">"برنامه <xliff:g id="APPLICATION">%1$s</xliff:g> (پردازش <xliff:g id="PROCESS">%2$s</xliff:g>) خطمشی StrictMode اجرایی خود را نقض کرده است."</string>
<string name="smv_process" msgid="5120397012047462446">"فرآیند <xliff:g id="PROCESS">%1$s</xliff:g> خطمشی StrictMode اجرای خودکار خود را نقض کرده است."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android در حال ارتقا است..."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index edfd4a3..926d67a 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Asteikko"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Näytä aina"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Ota tämä uudelleen käyttöön kohdassa Järjestelmäasetukset > Sovellukset > Ladattu."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei tue nykyistä näytön kokoasetusta ja saattaa toimia odottamattomalla tavalla."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Näytä aina"</string>
<string name="smv_application" msgid="3307209192155442829">"Sovellus <xliff:g id="APPLICATION">%1$s</xliff:g> (prosessi <xliff:g id="PROCESS">%2$s</xliff:g>) on rikkonut itse käyttöön ottamaansa StrictMode-käytäntöä."</string>
<string name="smv_process" msgid="5120397012047462446">"Prosessi <xliff:g id="PROCESS">%1$s</xliff:g> on rikkonut itse käyttöön ottamaansa StrictMode-käytäntöä."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Androidia päivitetään…"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 528f2f3..9ce9b60 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Redimensionner"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Toujours afficher"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Réactivez ce mode en accédant à Paramètres système > Applications > Téléchargements"</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas compatible avec le paramètre de taille d\'affichage actuel et peut se comporter de manière inattendue."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Toujours afficher"</string>
<string name="smv_application" msgid="3307209192155442829">"L\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>) a enfreint ses propres règles du mode strict."</string>
<string name="smv_process" msgid="5120397012047462446">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> a enfreint ses propres règles du mode strict."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Mise à jour d\'Android…"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 55606ce..cb91fb2 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Mise à l\'échelle"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Toujours afficher"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Réactivez ce mode en accédant à Paramètres système > Applications > Téléchargements"</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas compatible avec le paramètre de taille d\'affichage actuel et peut présenter un comportement inattendu."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Toujours afficher"</string>
<string name="smv_application" msgid="3307209192155442829">"L\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>) a enfreint ses propres règles du mode strict."</string>
<string name="smv_process" msgid="5120397012047462446">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> a enfreint ses propres règles du mode strict."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Mise à jour d\'Android…"</string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index f09eafb..bd857d8 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar sempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Volve activar esta función en Configuración do sistema > Aplicacións > Descargadas."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> non admite a configuración do tamaño de pantalla actual e quizais presente un comportamento inesperado."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar sempre"</string>
<string name="smv_application" msgid="3307209192155442829">"A aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) infrinxiu a súa política StrictMode autoaplicada."</string>
<string name="smv_process" msgid="5120397012047462446">"O proceso <xliff:g id="PROCESS">%1$s</xliff:g> infrinxiu a política StrictMode de aplicación automática."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Estase actualizando Android…"</string>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index 1970d3c..8115659 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"સ્કેલ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"હંમેશા બતાવો"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"આને સિસ્ટમ સેટિંગ્સ > ઍપ્લિકેશનો > ડાઉનલોડ કરેલમાં ફરીથી સક્ષમ કરો."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> વર્તમાન પ્રદર્શન કદની સેટિંગનું સમર્થન કરતું નથી અને અનપેક્ષિત રીતે વર્તી શકે છે."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"હંમેશાં બતાવો"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> ઍપ્લિકેશન (<xliff:g id="PROCESS">%2$s</xliff:g> પ્રક્રિયા)એ તેની સ્વ-લાગુ કરેલ StrictMode નીતિનું ઉલ્લંઘન કર્યું છે."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> પ્રક્રિયાએ તેની સ્વ-લાગુ કરેલ StrictMode નીતિનું ઉલ્લંઘન કર્યું છે."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android અપગ્રેડ થઈ રહ્યું છે..."</string>
diff --git a/core/res/res/values-hi-watch/styles_material.xml b/core/res/res/values-hi-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-hi-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?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.
+ -->
+
+<!--
+===============================================================
+ 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 styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 147e677..c8c8292 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"स्केल"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"हमेशा दिखाएं"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"इसे सिस्टम सेटिंग > Apps > डाउनलोड किए गए में पुन: सक्षम करें."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> वर्तमान स्क्रीन के आकार की सेटिंग का समर्थन नहीं करता है और अनपेक्षित रूप से व्यवहार कर सकता है."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"हमेशा दिखाएं"</string>
<string name="smv_application" msgid="3307209192155442829">"ऐप्स <xliff:g id="APPLICATION">%1$s</xliff:g> (प्रक्रिया <xliff:g id="PROCESS">%2$s</xliff:g>) ने उसकी स्वयं लागू होने वाली StrictMode नीति का उल्लंघन किया है."</string>
<string name="smv_process" msgid="5120397012047462446">"प्रक्रिया <xliff:g id="PROCESS">%1$s</xliff:g> ने उसकी स्व-प्रवर्तित StrictMode नीति का उल्लंघन किया है."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android अपग्रेड हो रहा है..."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index d1752c6..506cad2 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1038,6 +1038,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Mjerilo"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Uvijek prikaži"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Omogućiti to ponovo u Postavkama sustava > Aplikacije > Preuzimanja."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava trenutačnu postavku veličine zaslona i može se ponašati neočekivano."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Uvijek prikaži"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) prekršila je vlastito pravilo StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> prekršio je svoje vlastito pravilo StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android se nadograđuje…"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 73dc3c7..8950ec6 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skála"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mindig megjelenik"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Újbóli engedélyezés itt: Rendszerbeállítások > Alkalmazások > Letöltve."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás nem támogatja a képernyőméret jelenlegi beállításait, ezért nem várt módon viselkedhet."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Mindig megjelenik"</string>
<string name="smv_application" msgid="3307209192155442829">"A(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazás (<xliff:g id="PROCESS">%2$s</xliff:g> folyamat) megsértette az általa kényszerített Szigorú üzemmód irányelvet."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> folyamat megsértette az általa kényszerített Szigorú üzemmód irányelvet."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android frissítése folyamatban..."</string>
diff --git a/core/res/res/values-hy-rAM-watch/styles_material.xml b/core/res/res/values-hy-rAM-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-hy-rAM-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?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.
+ -->
+
+<!--
+===============================================================
+ 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 styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index d9aac5a..b9cd9ef 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Աստիճանակարգել"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Միշտ ցույց տալ"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Կրկին ակտիվացնել սա Համակարգի կարգավորումներում &gt Ծրագրեր > Ներբեռնումներ:"</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը չի աջակցում Էկրանի չափի ընթացիկ կարգավորումները, ինչի պատճառով կարող են խնդիրներ առաջանալ:"</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Միշտ ցուցադրել"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> ծրագիրը (գործընթաց <xliff:g id="PROCESS">%2$s</xliff:g>) խախտել է իր ինքնահարկադրված Խիստ ռեժիմ քաղաքականությունը:"</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> գործընթացը խախտել է իր ինքնահարկադրված Խիստ ռեժիմ քաղաքականությունը:"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android-ը նորացվում է..."</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 74efb2d..0211d41 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Selalu tampilkan"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktifkan kembali dialog ini di Setelan sistem > Apl > Terunduh."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak mendukung setelan Ukuran layar saat ini dan dapat menunjukkan perilaku yang tak diharapkan."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Selalu tampilkan"</string>
<string name="smv_application" msgid="3307209192155442829">"Apl <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) telah melanggar kebijakan StrictMode yang diberlakukannya sendiri."</string>
<string name="smv_process" msgid="5120397012047462446">"Proses <xliff:g id="PROCESS">%1$s</xliff:g> telah melanggar kebijakan StrictMode yang diberlakukan secara otomatis."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android sedang meningkatkan versi..."</string>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 25f9211..f759e92 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Breyta stærð"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Sýna alltaf"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Þú getur kveikt aftur á þessu undir Kerfisstillingar > Forrit > Sótt."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> styður ekki núverandi skjástærðarstillingu og gæti því ekki virkað sem skyldi."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Sýna alltaf"</string>
<string name="smv_application" msgid="3307209192155442829">"Forritið <xliff:g id="APPLICATION">%1$s</xliff:g> (ferli <xliff:g id="PROCESS">%2$s</xliff:g>) hefur brotið gegn eigin StrictMode-stefnu."</string>
<string name="smv_process" msgid="5120397012047462446">"Forritið <xliff:g id="PROCESS">%1$s</xliff:g> braut gegn eigin StrictMode-stefnu."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android er að uppfæra…"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 8318d45..9591262 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostra sempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Riattivala in Impostazioni di sistema > Applicazioni > Scaricate."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> non supporta le dimensioni di visualizzazione attualmente impostate e potrebbe comportarsi in modo imprevisto."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostra sempre"</string>
<string name="smv_application" msgid="3307209192155442829">"L\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) ha violato la norma StrictMode autoimposta."</string>
<string name="smv_process" msgid="5120397012047462446">"Il processo <xliff:g id="PROCESS">%1$s</xliff:g> ha violato la norma StrictMode autoimposta."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Aggiornamento di Android..."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index c1f5246..b1b7e04 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1061,6 +1061,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"שינוי קנה-מידה"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"הצג תמיד"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"אפשר תכונה זו מחדש ב\'הגדרות מערכת\' < Google Apps < \'הורדות\'."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> אינו תומך בהגדרת הגודל הנוכחית של התצוגה, והתנהגותו עשויה להיות בלתי צפויה."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"הצג תמיד"</string>
<string name="smv_application" msgid="3307209192155442829">"האפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g> (תהליך <xliff:g id="PROCESS">%2$s</xliff:g>) הפר את מדיניות StrictMode באכיפה עצמית שלו."</string>
<string name="smv_process" msgid="5120397012047462446">"התהליך <xliff:g id="PROCESS">%1$s</xliff:g> הפר את מדיניות StrictMode באכיפה עצמית."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android מבצע שדרוג…"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 99e88d1..4d49825 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"スケール"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"常に表示"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"[システム設定]>[アプリ]>[ダウンロード済み]で再度有効にします。"</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」は現在の [表示サイズ] 設定に対応していないため、予期しない動作が発生するおそれがあります。"</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"常に表示"</string>
<string name="smv_application" msgid="3307209192155442829">"アプリ「<xliff:g id="APPLICATION">%1$s</xliff:g>」(プロセス「<xliff:g id="PROCESS">%2$s</xliff:g>」)でStrictModeポリシー違反がありました。"</string>
<string name="smv_process" msgid="5120397012047462446">"プロセス<xliff:g id="PROCESS">%1$s</xliff:g>でStrictModeポリシー違反がありました。"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Androidをアップグレードしています..."</string>
diff --git a/core/res/res/values-ka-rGE-watch/styles_material.xml b/core/res/res/values-ka-rGE-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-ka-rGE-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?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.
+ -->
+
+<!--
+===============================================================
+ 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 styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 0c7c42d..79cfa9d 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"მასშტაბი"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"ყოველთვის ჩვენება"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"ხელახალი გააქტიურება განყოფილებაში: სისტემის პარამეტრები > აპები > ჩამოტვირთულები."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის მიერ ეკრანის ამჟამინდელი პარამეტრები მხარდაუჭერელია და შეიძლება არასათანადოდ იმუშაოს."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"ყოველთვის ჩვენება"</string>
<string name="smv_application" msgid="3307209192155442829">"აპმა <xliff:g id="APPLICATION">%1$s</xliff:g> (პროცესი <xliff:g id="PROCESS">%2$s</xliff:g>) დაარღვია საკუთარი StrictMode დებულება."</string>
<string name="smv_process" msgid="5120397012047462446">"ამ პროცესმა <xliff:g id="PROCESS">%1$s</xliff:g> დააზიანა საკუთარი StrictMode დებულება."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android ახალ ვერსიაზე გადადის…"</string>
diff --git a/core/res/res/values-kk-rKZ-watch/styles_material.xml b/core/res/res/values-kk-rKZ-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-kk-rKZ-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?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.
+ -->
+
+<!--
+===============================================================
+ 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 styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index 3f8ee05..e6146af 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Меже"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Үнемі көрсету"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Мұны «Жүйелік параметрлер» > «Қолданбалар» > «Жүктелгендер» тармағында қосыңыз."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасында \"Дисплей өлшемі\" параметрінің таңдалған мәніне қолдау көрсетілмейді, сондықтан дұрыс жұмыс істемеуі мүмкін."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Үнемі көрсету"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасы (<xliff:g id="PROCESS">%2$s</xliff:g> процесі) өзі қолданған StrictMode саясатын бұзды."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> үрдісі өздігінен күшіне енген ҚатаңРежим ережесін бұзды."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android жаңартылуда…"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index aa7b35a..a73caf3 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -1017,6 +1017,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"មាត្រដ្ឋាន"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"បង្ហាញជានិច្ច"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"បើកវាឡើងវិញក្នុងការកំណត់ប្រព័ន្ធ > កម្មវិធី > ទាញយក។"</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> មិនគាំទ្រការកំណត់ទំហំនៃការបង្ហាញបច្ចុប្បន្ន និងអាចមានសកម្មភាពខុសពីការរំពឹងទុក។"</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"បង្ហាញជានិច្ច"</string>
<string name="smv_application" msgid="3307209192155442829">"កម្មវិធី <xliff:g id="APPLICATION">%1$s</xliff:g> (ដំណើរការ <xliff:g id="PROCESS">%2$s</xliff:g>) បានបំពានគោលនយោបាយរបៀបតឹងរ៉ឹងអនុវត្តដោយខ្លួនឯង។"</string>
<string name="smv_process" msgid="5120397012047462446">"ដំណើរការ <xliff:g id="PROCESS">%1$s</xliff:g> បានបំពានគោលនយោបាយរបៀបតឹងរឹងបង្ខំដោយខ្លួនឯង"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android កំពុងធ្វើបច្ចុប្បន្នភាព..."</string>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index d5e8fa2..cbb2864 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"ಮಾಪಕ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"ಯಾವಾಗಲೂ ತೋರಿಸಿ"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"ಸಿಸ್ಟಂ ಸೆಟ್ಟಿಂಗ್ಗಳು > ಅಪ್ಲಿಕೇಶನ್ಗಳು > ಡೌನ್ಲೋಡ್ ಆಗಿರುವುದರಲ್ಲಿ ಇದನ್ನು ಮರು ಸಕ್ರಿಯಗೊಳಿಸಿ."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಪ್ರಸ್ತುತ ಪ್ರದರ್ಶನ ಗಾತ್ರದ ಸೆಟ್ಟಿಂಗ್ ಅನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ ಮತ್ತು ಅನಿರೀಕ್ಷಿತವಾಗಿ ವರ್ತಿಸಬಹುದು."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"ಯಾವಾಗಲೂ ತೋರಿಸು"</string>
<string name="smv_application" msgid="3307209192155442829">"ಅಪ್ಲಿಕೇಶನ್ <xliff:g id="APPLICATION">%1$s</xliff:g> (ಪ್ರಕ್ರಿಯೆಯು <xliff:g id="PROCESS">%2$s</xliff:g>) ತನ್ನ ಸ್ವಯಂ-ಜಾರಿ ಕಠಿಣ ಮೋಡ್ ನೀತಿಯನ್ನು ಉಲ್ಲಂಘನೆ ಮಾಡಿದೆ."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> ಪ್ರಕ್ರಿಯೆಯು ತನ್ನ ಸ್ವಯಂ-ಜಾರಿ ಕಠಿಣ ಮೋಡ್ ನೀತಿಯನ್ನು ಉಲ್ಲಂಘನೆ ಮಾಡಿದೆ."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android ಅಪ್ಗ್ರೇಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ…"</string>
diff --git a/core/res/res/values-ko-watch/styles_material.xml b/core/res/res/values-ko-watch/styles_material.xml
index 0755eac..36a459d 100644
--- a/core/res/res/values-ko-watch/styles_material.xml
+++ b/core/res/res/values-ko-watch/styles_material.xml
@@ -31,5 +31,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"후보"</font></string>
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 1c165f9..69cbad7 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"배율"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"항상 표시"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"시스템 설정 > 앱 > 다운로드로 이동하여 이 모드를 다시 사용하도록 설정합니다."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱은 현재 디스플레이 크기 설정을 지원하지 않으며 예기치 않게 동작할 수 있습니다."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"항상 표시"</string>
<string name="smv_application" msgid="3307209192155442829">"앱 <xliff:g id="APPLICATION">%1$s</xliff:g>(프로세스 <xliff:g id="PROCESS">%2$s</xliff:g>)이(가) 자체 시행 StrictMode 정책을 위반했습니다."</string>
<string name="smv_process" msgid="5120397012047462446">"프로세스(<xliff:g id="PROCESS">%1$s</xliff:g>)가 자체 시행 StrictMode 정책을 위반했습니다."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android 업그레이드 중.."</string>
diff --git a/core/res/res/values-ky-rKG-watch/styles_material.xml b/core/res/res/values-ky-rKG-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-ky-rKG-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?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.
+ -->
+
+<!--
+===============================================================
+ 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 styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index ada25dc..5f97975 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Шкала"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Ар дайым көрсөтүлсүн"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Муну тутум жөндөөлөрүнөн кайра иштетүү > Колдонмолор > Жүктөлүп алынган."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу учурдагы дисплей өлчөмүнүн жөндөөлөрүн колдоого албагандыктан, күтүүсүз аракеттерди жасашы мүмкүн."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Ар дайым көрсөтүлсүн"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосу (<xliff:g id="PROCESS">%2$s</xliff:g> процесси) өз алдынча иштеткен StrictMode саясатын бузду."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> процесси өзүнүн мажбурланган StrictMode саясатын бузуп койду."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android жаңыртылууда…"</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index b003764..1a43ea5 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"ຂະໜາດ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"ສະແດງຕະຫຼອດເວລາ"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"ເປີດການເຮັດວຽກນີ້ຄືນໄດ້ໃນ ການຕັ້ງຄ່າລະບົບ > ແອັບຯ > ດາວໂຫລດແລ້ວ"</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ່ຮອງຮັບການຕັ້ງຄ່າຂະໜາດສະແດງຜົນປັດຈຸບັນ ແລະ ອາດມີຄວາມຜິດພາດໄດ້."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"ສະແດງທຸກເທື່ອ"</string>
<string name="smv_application" msgid="3307209192155442829">"ແອັບຯ <xliff:g id="APPLICATION">%1$s</xliff:g> (ໂປຣເຊສ <xliff:g id="PROCESS">%2$s</xliff:g>) ໄດ້ລະເມີດນະໂຍບາຍ StrictMode ທີ່ບັງຄັບໃຊ້ດ້ວຍໂຕເອງ."</string>
<string name="smv_process" msgid="5120397012047462446">"ໂປຣເຊສ <xliff:g id="PROCESS">%1$s</xliff:g> ລະເມີດນະໂຍບາຍບັງຄັບໃຊ້ເອງ StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"ກຳລັງອັບເກຣດ Android..."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 0e4c1d6..c4c2e26 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1061,6 +1061,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Mastelis"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Visada rodyti"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Įgalinkite jį iš naujo nuėję į „Sistemos nustatymai“ > „Programos“ > „Atsisiųsta“."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"Programoje „<xliff:g id="APP_NAME">%1$s</xliff:g>“ nepalaikomas dabartinis ekrano dydžio nustatymas ir ji gali netinkamai veikti."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Visada rodyti"</string>
<string name="smv_application" msgid="3307209192155442829">"Programa „<xliff:g id="APPLICATION">%1$s</xliff:g>“ (procesas „<xliff:g id="PROCESS">%2$s</xliff:g>“) pažeidė savo vykdomą „StrictMode“ politiką."</string>
<string name="smv_process" msgid="5120397012047462446">"„<xliff:g id="PROCESS">%1$s</xliff:g>“ procesas pažeidė savo vykdomą „StrictMode“ politiką."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"„Android“ naujovinama..."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 5b91848..881297f 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1038,6 +1038,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Mērogs"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Rādīt vienmēr"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Atkārtoti iespējojiet šeit: Sistēmas iestatījumi > Lietotnes > Lejupielādētās."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"Lietotnē <xliff:g id="APP_NAME">%1$s</xliff:g> netiek atbalstīts pašreizējais displeja lieluma iestatījums, tādēļ tā var tikt attēlota neparedzētā veidā."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Rādīt vienmēr"</string>
<string name="smv_application" msgid="3307209192155442829">"Lietotne <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) ir pārkāpusi savu pašieviesto StrictMode politiku."</string>
<string name="smv_process" msgid="5120397012047462446">"Process <xliff:g id="PROCESS">%1$s</xliff:g> ir pārkāpis savu pašieviesto StrictMode politiku."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Notiek Android jaunināšana..."</string>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index 010958f..83081ff 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Размер"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Покажи секогаш"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Повторно овозможете го ова во Системски поставки > Апликации > Преземено."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> не ја поддржува тековната поставка за големина на екранот и може да се однесува непредвидено."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Секогаш прикажувај"</string>
<string name="smv_application" msgid="3307209192155442829">"Апликацијата <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) ја прекрши политиката StrictMode што си ја наметна врз себеси."</string>
<string name="smv_process" msgid="5120397012047462446">"Процесот <xliff:g id="PROCESS">%1$s</xliff:g> ја прекрши својата самонаметната политика на строг режим."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android се ажурира…"</string>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index 7120cad..6739d86 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"സ്കെയിൽ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"എപ്പോഴും പ്രദര്ശിപ്പിക്കുക"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"സിസ്റ്റം ക്രമീകരണങ്ങൾ > അപ്ലിക്കേഷനുകൾ > ഡൗൺലോഡുചെയ്തവ എന്നതിൽ ഇത് വീണ്ടും പ്രവർത്തനക്ഷമമാക്കുക."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"നിലവിലെ ഡിസ്പ്ലേ വലുപ്പ ക്രമീകരണത്തെ <xliff:g id="APP_NAME">%1$s</xliff:g> പിന്തുണയ്ക്കുന്നില്ല, അതിനാൽ പ്രതീക്ഷിക്കാത്ത തരത്തിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കാം."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"എല്ലായ്പ്പോഴും ദൃശ്യമാക്കുക"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> എന്ന അപ്ലിക്കേഷൻ (<xliff:g id="PROCESS">%2$s</xliff:g> പ്രോസസ്സ്) അതിന്റെ സ്വയം നിർബന്ധിത StrictMode നയം ലംഘിച്ചു."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> എന്ന പ്രോസസ്സ് അതിന്റെ സ്വയം നടപ്പിലാക്കിയ StrictMode നയം ലംഘിച്ചു."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android അപ്ഗ്രേഡുചെയ്യുന്നു…"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index ae9b7ef..e86960b 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Цар хэмжээ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Байнга харуулах"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Энийг Системийн тохиргоо > Апп > Татаж авсан дотроос дахин идэвхтэй болгох боломжтой."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь Дэлгэцийн хэмжээний одоогийн тохиргоог дэмждэггүй учир буруу ажиллаж болзошгүй."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Байнга харуулах"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> апп (<xliff:g id="PROCESS">%2$s</xliff:g> процесс) өөрийнхөө StrictMode бодлогыг зөрчив."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> процесс өөрийнхөө StrictMode бодлогыг зөрчив."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Андройдыг дэвшүүлж байна…"</string>
diff --git a/core/res/res/values-mr-rIN-watch/styles_material.xml b/core/res/res/values-mr-rIN-watch/styles_material.xml
index 3c2513e..36a459d 100644
--- a/core/res/res/values-mr-rIN-watch/styles_material.xml
+++ b/core/res/res/values-mr-rIN-watch/styles_material.xml
@@ -31,5 +31,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"उमेद्वार"</font></string>
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
</resources>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 233a529..c56ad32 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"स्केल"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"नेहमी दर्शवा"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"सिस्टीम सेटिंग्ज > Apps > डाउनलोड केलेले मध्ये हे पुन्हा-सक्षम करा."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> वर्तमान प्रदर्शन आकार सेटिंगला समर्थन देत नाही आणि अनपेक्षित वर्तन करू शकते."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"नेहमी दर्शवा"</string>
<string name="smv_application" msgid="3307209192155442829">"अॅप <xliff:g id="APPLICATION">%1$s</xliff:g> (प्रक्रिया <xliff:g id="PROCESS">%2$s</xliff:g>) ने तिच्या स्वयं-लागू केलेल्या StrictMode धोरणाचे उल्लंघन केले आहे."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> प्रक्रियेने तिच्या स्वतः-लागू केलेल्या StrictMode धोरणाचे उल्लंघन केले."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android श्रेणीसुधारित होत आहे..."</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index e48d7d6..541a8b3 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Sentiasa tunjukkan"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Dayakan semula kod kompak ini tetapan Sistem > Apl > Dimuat turun."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak menyokong tetapan saiz Paparan semasa dan mungkin menunjukkan gelagat yang tidak dijangka."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Sentiasa tunjukkan"</string>
<string name="smv_application" msgid="3307209192155442829">"Apl <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) telah melanggar dasar Mod Tegasnya sendiri."</string>
<string name="smv_process" msgid="5120397012047462446">"Proses <xliff:g id="PROCESS">%1$s</xliff:g> telah melanggar dasar Mod Tegasnya sendiri."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android sedang menaik taraf..."</string>
diff --git a/core/res/res/values-my-rMM-watch/styles_material.xml b/core/res/res/values-my-rMM-watch/styles_material.xml
index 616e13e..36a459d 100644
--- a/core/res/res/values-my-rMM-watch/styles_material.xml
+++ b/core/res/res/values-my-rMM-watch/styles_material.xml
@@ -31,5 +31,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"ကိုယ်စားလှယ်များ"</font></string>
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
</resources>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 72fc86e..e4fdfe4 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"စကေး"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"အမြဲပြသရန်"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"ဒါကို စနစ် ဆက်တင်များထဲ ပြန်ဖွင့်ပေးရန် > Apps > ဒေါင်းလုဒ် လုပ်ပြီး။"</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် လက်ရှိ မျက်နှာပြင်အရွယ်အစားကို ပံ့ပိုးထားခြင်း မရှိပါ။ မမျှော်လင့်နိုင်သည့် ချွတ်ယွင်းချက်များ ဖြစ်ပေါ်နိုင်ပါသည်။"</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"အမြဲပြပါ"</string>
<string name="smv_application" msgid="3307209192155442829">"app <xliff:g id="APPLICATION">%1$s</xliff:g> (လုပ်ငန်းစဉ် <xliff:g id="PROCESS">%2$s</xliff:g>) က ကိုယ်တိုင် ပြဌာန်းခဲ့သည့် StrictMode မူဝါဒကို ချိုးဖောက်ခဲ့သည်။"</string>
<string name="smv_process" msgid="5120397012047462446">"ဤ<xliff:g id="PROCESS">%1$s</xliff:g>ဖြစ်စဥ်မှာ ကိုယ်တိုင်အကျိုးသက်ရောက်သော StrictModeမူဝါဒအား ချိုးဖောက်သည်"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"အန်ဒရွိုက်ကို မွမ်းမံနေ…"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index c530593..55c78a7 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Vis alltid"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reaktiver dette i systeminnstillingene > Apper > Nedlastet."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> støtter ikke den nåværende innstillingen for skjermstørrelse og fungerer kanskje ikke som den skal."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Vis alltid"</string>
<string name="smv_application" msgid="3307209192155442829">"Appen <xliff:g id="APPLICATION">%1$s</xliff:g> (prosessen <xliff:g id="PROCESS">%2$s</xliff:g>) har brutt de selvpålagte StrictMode-retningslinjene."</string>
<string name="smv_process" msgid="5120397012047462446">"Prosessen<xliff:g id="PROCESS">%1$s</xliff:g> har brutt de selvpålagte StrictMode-retningslinjene."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android oppgraderes …"</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 0f4e99c..ef9fc39 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -1021,6 +1021,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"स्केल"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"सधैँ देखाउनुहोस्"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"प्रणाली सेटिङहरूमा यसलाई पुनःसक्षम गराउनुहोस् > अनुप्रयोगहरू > डाउनलोड गरेको।"</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले हालको प्रदर्शनको आकार सम्बन्धी सेटिङलाई समर्थन गर्दैन र अप्रत्याशित तरिकाले व्यवहार गर्न सक्छ।"</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"सधैँ देखाउनुहोस्"</string>
<string name="smv_application" msgid="3307209192155442829">"अनुप्रयोग <xliff:g id="APPLICATION">%1$s</xliff:g> (प्रक्रिया <xliff:g id="PROCESS">%2$s</xliff:g>) ले यसको स्वयं-लागु गरिएको स्ट्रिटमोड नीति उलङ्घन गरेको छ।"</string>
<string name="smv_process" msgid="5120397012047462446">"प्रक्रिया <xliff:g id="PROCESS">%1$s</xliff:g> यसको आफ्नै कडामोड नीतिका कारण उल्लङ्घन गरिएको छ।"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"एन्ड्रोइड अपग्रेड हुँदैछ…"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index cce6c09..f93320e 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Schaal"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Altijd weergeven"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"U kunt dit opnieuw inschakelen via Systeeminstellingen > Apps > Gedownload."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> biedt geen ondersteuning voor de huidige instelling voor weergavegrootte en kan onverwacht gedrag vertonen."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Altijd weergeven"</string>
<string name="smv_application" msgid="3307209192155442829">"De app <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) heeft het zelf afgedwongen StrictMode-beleid geschonden."</string>
<string name="smv_process" msgid="5120397012047462446">"Het proces <xliff:g id="PROCESS">%1$s</xliff:g> heeft het zelf afgedwongen StrictMode-beleid geschonden."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android wordt bijgewerkt..."</string>
diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
index 26b7db1..881a78d 100644
--- a/core/res/res/values-pa-rIN/strings.xml
+++ b/core/res/res/values-pa-rIN/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"ਸਕੇਲ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"ਹਮੇਸ਼ਾਂ ਦਿਖਾਓ"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"ਸਿਸਟਮ ਸੈਟਿੰਗਾਂ > ਐਪਸ > ਡਾਊਨਲੋਡ ਕੀਤਿਆਂ ਵਿੱਚ ਇਸਨੂੰ ਮੁੜ-ਸਮਰੱਥ ਬਣਾਓ।"</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਵਰਤਮਾਨ ਡਿਸਪਲੇ ਆਕਾਰ ਸੈਟਿੰਗ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ ਹੈ ਅਤੇ ਅਣਕਿਆਸੇ ਤੌਰ \'ਤੇ ਵਿਹਾਰ ਕਰ ਸਕਦੀ ਹੈ।"</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"ਹਮੇਸ਼ਾ ਵਿਖਾਓ"</string>
<string name="smv_application" msgid="3307209192155442829">"ਐਪ <xliff:g id="APPLICATION">%1$s</xliff:g> (ਪ੍ਰਕਿਰਿਆ<xliff:g id="PROCESS">%2$s</xliff:g>) ਨੇ ਆਪਣੀ ਖੁਦ-ਲਾਗੂ ਕੀਤੀ ਸਟ੍ਰਿਕਟਮੋਡ ਨੀਤੀ ਦੀ ਉਲੰਘਣਾ ਕੀਤੀ ਹੈ।"</string>
<string name="smv_process" msgid="5120397012047462446">"ਪ੍ਰਕਿਰਿਆ <xliff:g id="PROCESS">%1$s</xliff:g> ਨੇ ਆਪਣੀ ਖੁਦ-ਲਾਗੂ ਕੀਤੀ ਸਟ੍ਰਿਕਟਮੋਡ ਨੀਤੀ ਦੀ ਉਲੰਘਣਾ ਕੀਤੀ ਹੈ।"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android ਅਪਗ੍ਰੇਡ ਕਰ ਰਿਹਾ ਹੈ…"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 25638a5..54104e1 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1061,6 +1061,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Zawsze pokazuj"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Włącz ponownie, wybierając Ustawienia systemowe > Aplikacje > Pobrane."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> nie obsługuje obecnie ustawionego rozmiaru wyświetlacza i może działać niestabilnie."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Zawsze pokazuj"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) naruszyła wymuszone przez siebie zasady StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> naruszył wymuszone przez siebie zasady StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android jest uaktualniany..."</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 18c6d3e..5f15c0d 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar sempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reativar isso em Configurações do sistema > Apps > Transferidos."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com a configuração atual de tamanho de exibição e pode se comportar de forma inesperada."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar sempre"</string>
<string name="smv_application" msgid="3307209192155442829">"O app <xliff:g id="APPLICATION">%1$s</xliff:g>, processo <xliff:g id="PROCESS">%2$s</xliff:g>, violou a política StrictMode imposta automaticamente."</string>
<string name="smv_process" msgid="5120397012047462446">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> violou a política StrictMode imposta automaticamente."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"O Android está sendo atualizado..."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 1530b4f..e540d2c 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar sempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reative este modo nas Definições do Sistema > Aplicações > Transferidas."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> não suporta a definição de Tamanho do ecrã atual e pode ter um comportamento inesperado."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar sempre"</string>
<string name="smv_application" msgid="3307209192155442829">"A aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) violou a política StrictMode auto-imposta."</string>
<string name="smv_process" msgid="5120397012047462446">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> violou a política StrictMode auto-imposta."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"O Android está a ser atualizado..."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 18c6d3e..5f15c0d 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar sempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reativar isso em Configurações do sistema > Apps > Transferidos."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com a configuração atual de tamanho de exibição e pode se comportar de forma inesperada."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar sempre"</string>
<string name="smv_application" msgid="3307209192155442829">"O app <xliff:g id="APPLICATION">%1$s</xliff:g>, processo <xliff:g id="PROCESS">%2$s</xliff:g>, violou a política StrictMode imposta automaticamente."</string>
<string name="smv_process" msgid="5120397012047462446">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> violou a política StrictMode imposta automaticamente."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"O Android está sendo atualizado..."</string>
diff --git a/core/res/res/values-ro-watch/styles_material.xml b/core/res/res/values-ro-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-ro-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?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.
+ -->
+
+<!--
+===============================================================
+ 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 styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 2d41ae6..47e59d4 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1038,6 +1038,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scară"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Afișați întotdeauna"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reactivați acest mod din Setări de sistem > Aplicații > Descărcate."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu acceptă setarea actuală pentru Dimensiunea afișării și este posibil să aibă un comportament neașteptat."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Afișează întotdeauna"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplicația <xliff:g id="APPLICATION">%1$s</xliff:g> (procesul <xliff:g id="PROCESS">%2$s</xliff:g>) a încălcat propria politică StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Procesul <xliff:g id="PROCESS">%1$s</xliff:g> a încălcat propria politică StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android trece la o versiune superioară..."</string>
diff --git a/core/res/res/values-ru-watch/styles_material.xml b/core/res/res/values-ru-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-ru-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?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.
+ -->
+
+<!--
+===============================================================
+ 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 styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 16c5752..4921bc9 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1061,6 +1061,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Масштаб"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Всегда показывать"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Включить эту функцию можно в меню \"Настройки > Приложения > Загруженные\"."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" не поддерживает выбранный масштаб изображения на экране и может работать некорректно."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Всегда показывать"</string>
<string name="smv_application" msgid="3307209192155442829">"Приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" (процесс: <xliff:g id="PROCESS">%2$s</xliff:g>) нарушило собственную политику StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Процесс <xliff:g id="PROCESS">%1$s</xliff:g> нарушил собственную политику StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Обновление Android..."</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 0c28121..4134ab0 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -1017,6 +1017,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"පරිමාණය"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"සැමවිටම පෙන්වන්න"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"පද්ධති සැකසීම් තුළ මෙය නැවත ක්රියාත්මක කරන්න > යෙදුම් > බාගන්නා ලදි."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> වත්මන් සංදර්ශක තරම සඳහා සහාය නොදක්වන අතර අනපේක්ෂිත ලෙස හැසිරීමට හැකිය."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"සැම විටම පෙන්වන්න"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> යෙදුම (<xliff:g id="PROCESS">%2$s</xliff:g> ක්රියාවලිය) එහි StrictMode කොන්දේසිය උල්ලංඝනය කර ඇත."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> ක්රියාවලිය එහි StrictMode කොන්දේසිය උල්ලංඝනය කර ඇත."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android උත්ශ්රේණි වෙමින් පවතී..."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 89d762c..89bc983 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1061,6 +1061,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Prispôsobiť veľkosť"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Vždy zobraziť"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Povoľte to znova v sekcii Nastavenia systému > Aplikácie > Stiahnuté súbory."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> aktuálne nastavenie veľkosti zobrazenia nepodporuje a môže sa správať neočakávane."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Vždy zobrazovať"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikácia <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) porušila svoje vlastné vynútené pravidlá StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> porušil svoje vlastné vynútené pravidlá StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Prebieha inovácia systému Android..."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 051e4da..fcd84fe 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1061,6 +1061,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Lestvica"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Vedno pokaži"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Znova omogočite to v sistemskih nastavitvah > Aplikacije > Preneseno."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podpira trenutne nastavitve velikosti zaslona, kar lahko vodi v nepričakovano delovanje."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Vedno pokaži"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) krši svoj samouveljavljiv pravilnik o strogem načinu."</string>
<string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> krši svoj samoizvedljivi pravilnik o strogem načinu."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Poteka nadgradnja Androida ..."</string>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index ca17450..f4376254 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Shkalla"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Shfaq gjithnjë"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktivizoje sërish këtë te \"Cilësimet e sistemit\" > \"Aplikacionet\" > \"Të shkarkuara\"."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk mbështet cilësimin aktual të madhësisë së ekranit dhe mund të shfaqë sjellje të papritura."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Shfaq gjithmonë"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikacioni <xliff:g id="APPLICATION">%1$s</xliff:g> (procesi <xliff:g id="PROCESS">%2$s</xliff:g>) ka shkelur politikën e tij të vetë-imponuar \"Modaliteti i ashpër\" (StrictMode)."</string>
<string name="smv_process" msgid="5120397012047462446">"Procesi <xliff:g id="PROCESS">%1$s</xliff:g> ka shkelur politikën e tij të vetë-imponuar \"Modaliteti i rreptë\" (StrictMode)"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"\"Androidi\" po përditësohet…"</string>
diff --git a/core/res/res/values-sr-watch/styles_material.xml b/core/res/res/values-sr-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-sr-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?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.
+ -->
+
+<!--
+===============================================================
+ 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 styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 40fe943..8cadc1d 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1038,6 +1038,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Размера"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Увек приказуј"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Поново омогућите у менију Системска подешавања > Апликације > Преузето."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> не подржава тренутно подешавање величине приказа и може да се понаша неочекивано."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Увек приказуј"</string>
<string name="smv_application" msgid="3307209192155442829">"Апликација <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) је прекршила самонаметнуте StrictMode смернице."</string>
<string name="smv_process" msgid="5120397012047462446">"Процес <xliff:g id="PROCESS">%1$s</xliff:g> је прекршио самонаметнуте StrictMode смернице."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android се надограђује…"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 2168d96d6..70ca025 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Anpassning"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Visa alltid"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktivera detta igen i Systeminställningar > Appar > Hämtat."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> har inte stöd för den nuvarande inställningen för skärmstorlek och kanske inte fungerar som förväntat."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Visa alltid"</string>
<string name="smv_application" msgid="3307209192155442829">"Appen <xliff:g id="APPLICATION">%1$s</xliff:g> (processen <xliff:g id="PROCESS">%2$s</xliff:g>) har brutit mot sin egen StrictMode-policy."</string>
<string name="smv_process" msgid="5120397012047462446">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> har brutit mot sin egen StrictMode-policy."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android uppgraderas ..."</string>
diff --git a/core/res/res/values-sw-watch/styles_material.xml b/core/res/res/values-sw-watch/styles_material.xml
index 2e3f715..01392b2 100644
--- a/core/res/res/values-sw-watch/styles_material.xml
+++ b/core/res/res/values-sw-watch/styles_material.xml
@@ -31,5 +31,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"vipengee"</font></string>
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"yanayopendekezwa"</font></string>
</resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 7e6f0338..34a7570 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1013,6 +1013,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Kipimo"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Onyesha kila wakati"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Wezesha tena hii katika mipangilio ya Mfumo > Programu > iliyopakuliwa."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> haiwezi kutumia mipangilio ya sasa ya ukubwa wa Skrini na huenda isifanye kazi vizuri."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Onyesha kila wakati"</string>
<string name="smv_application" msgid="3307209192155442829">"Programu <xliff:g id="APPLICATION">%1$s</xliff:g> (utaratibu <xliff:g id="PROCESS">%2$s</xliff:g>) imeenda kinyume na sera yake ya StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Shughuli ya <xliff:g id="PROCESS">%1$s</xliff:g> imeenda kinyume na kulazimisha sera yake ya StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Toleo jipya la Android linawekwa..."</string>
diff --git a/core/res/res/values-ta-rIN-watch/styles_material.xml b/core/res/res/values-ta-rIN-watch/styles_material.xml
new file mode 100644
index 0000000..d4605e6
--- /dev/null
+++ b/core/res/res/values-ta-rIN-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?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.
+ -->
+
+<!--
+===============================================================
+ 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 styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"கேன்டிடேட்ஸ்"</font></string>
+</resources>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index 1212bdd..f6daa74 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"அளவு"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"எப்போதும் காட்டு"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"சிஸ்டம் அமைப்பு > பயன்பாடுகள் > பதிவிறக்கம் என்பதில் இதை மீண்டும் இயக்கவும்."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"தற்போதைய திரை அளவு அமைப்பை <xliff:g id="APP_NAME">%1$s</xliff:g> ஆதரிக்காததால், அது வழக்கத்திற்கு மாறாகச் செயல்படக்கூடும்."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"எப்போதும் காட்டு"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> பயன்பாடு (செயல்முறை <xliff:g id="PROCESS">%2$s</xliff:g>), தனது சுய-செயலாக்க StrictMode கொள்கையை மீறியது."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> செயல்முறை, தனது சுய-செயலாக்க StrictMode கொள்கையை மீறியது."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android மேம்படுத்தப்படுகிறது…"</string>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 675f824..05c3423 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"ప్రమాణం"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"ఎల్లప్పుడూ చూపు"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"సిస్టమ్ సెట్టింగ్లు > అనువర్తనాలు > డౌన్లోడ్ చేసినవిలో దీన్ని పునఃప్రారంభించండి."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ప్రస్తుత ప్రదర్శన పరిమాణ సెట్టింగ్కు మద్దతు ఇవ్వదు, దీని వలన ఊహించని సమస్యలు తలెత్తవచ్చు."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"ఎల్లప్పుడూ చూపు"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> అనువర్తనం (<xliff:g id="PROCESS">%2$s</xliff:g> ప్రాసెస్) అది స్వయంగా అమలు చేసే ఖచ్చితమైన మోడ్ విధానాన్ని ఉల్లంఘించింది."</string>
<string name="smv_process" msgid="5120397012047462446">"ప్రక్రియ <xliff:g id="PROCESS">%1$s</xliff:g> అది స్వయంగా అమలు చేసే ఖచ్చితమైన మోడ్ విధానాన్ని ఉల్లంఘించింది."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android అప్గ్రేడ్ అవుతోంది…"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index c21d628..cb989ad 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"สเกล"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"แสดงเสมอ"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"เปิดใช้งานอีกครั้งในการตั้งค่าระบบ > แอปพลิเคชัน > ดาวน์โหลด"</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ไม่สนับสนุนการตั้งค่าขนาดการแสดงผลปัจจุบันและอาจแสดงผลผิดปกติ"</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"แสดงเสมอ"</string>
<string name="smv_application" msgid="3307209192155442829">"แอปพลิเคชัน <xliff:g id="APPLICATION">%1$s</xliff:g> (กระบวนการ <xliff:g id="PROCESS">%2$s</xliff:g>) ละเมิดนโยบาย StrictMode ที่บังคับใช้ด้วยตัวเอง"</string>
<string name="smv_process" msgid="5120397012047462446">"กระบวนการ <xliff:g id="PROCESS">%1$s</xliff:g> ละเมิดนโยบาย StrictMode ที่บังคับใช้ด้วยตัวเอง"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"กำลังอัปเกรด Android ..."</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 269f249..354c210 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Sukat"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Palaging ipakita"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Muling paganahin ito sa mga setting ng System > Apps > Na-download."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"Hindi sinusuportahan ng <xliff:g id="APP_NAME">%1$s</xliff:g> ang kasalukuyang setting ng laki ng Display at maaaring may mangyaring hindi inaasahan."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Palaging ipakita"</string>
<string name="smv_application" msgid="3307209192155442829">"Ang app na <xliff:g id="APPLICATION">%1$s</xliff:g> (prosesong <xliff:g id="PROCESS">%2$s</xliff:g>) ay lumabag sa sarili nitong ipinapatupad na patakarang StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Ang prosesong <xliff:g id="PROCESS">%1$s</xliff:g> ay lumabag sa sarili nitong ipinapatupad na patakarang StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Nag-a-upgrade ang Android…"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 6c88fb2..f8b0e46 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Ölçek"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Her zaman göster"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Bunu Sistem ayarları > Uygulamalar > İndirilenler bölümünden yeniden etkinleştirin."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> geçerli Ekran boyutu ayarını desteklemiyor ve beklenmedik bir şekilde davranabilir."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Her zaman göster"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulaması (<xliff:g id="PROCESS">%2$s</xliff:g> işlemi) kendiliğinden uyguladığı StrictMode politikasını ihlal etti."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> işlemi kendiliğinden uyguladığı StrictMode politikasını ihlal etti."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android yeni sürüme geçiriliyor..."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 15759b0..122675b 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1061,6 +1061,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Масштаб"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Завжди показувати"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Знову ввімкнути це в меню Налаштування системи > Програми > Завантажені."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> не підтримує поточне налаштування розміру екрана та може працювати неналежним чином."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Завжди показувати"</string>
<string name="smv_application" msgid="3307209192155442829">"Програма <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) порушила свою самозастосовну політику StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Процес <xliff:g id="PROCESS">%1$s</xliff:g> порушив свою самозастосовну політику StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android оновлюється..."</string>
diff --git a/core/res/res/values-ur-rPK-watch/styles_material.xml b/core/res/res/values-ur-rPK-watch/styles_material.xml
new file mode 100644
index 0000000..e569c7c
--- /dev/null
+++ b/core/res/res/values-ur-rPK-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?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.
+ -->
+
+<!--
+===============================================================
+ 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 styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"امیدواران"</font></string>
+</resources>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index 4ae5cbf..4b95d40 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"پیمانہ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"ہمیشہ دکھائیں"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"سسٹم ترتیبات > ایپس > ڈاؤن لوڈ کردہ میں اسے دوبارہ فعال کریں۔"</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> میں موجودہ ڈسپلے سائز ترتیبات کی معاونت نہیں ہے اور ہو سکتا ہے غیر متوقع طریقے سے کام کرے۔"</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"ہمیشہ دکھائیں"</string>
<string name="smv_application" msgid="3307209192155442829">"ایپ <xliff:g id="APPLICATION">%1$s</xliff:g> (کارروائی <xliff:g id="PROCESS">%2$s</xliff:g>) نے خود نافذ کی گئی StrictMode پالیسی کی خلاف ورزی کی ہے۔"</string>
<string name="smv_process" msgid="5120397012047462446">"کارروائی <xliff:g id="PROCESS">%1$s</xliff:g> نے اپنی ذاتی طور پر نافذ کردہ StrictMode پلیسی کی خلاف ورزی کی ہے۔"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android اپ گریڈ ہو رہا ہے…"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index d777ea0..c833d0f 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -325,9 +325,9 @@
<string name="permdesc_receiveBootCompleted" product="tv" msgid="4525890122209673621">"Ilovaga tizim ishga tushishi bilanoq o‘zi ham ishga tushadigan qilib qo‘yish huquqini beradi. Buning natijasida televizorning ishga tushishi sekinlashishi hamda ilovaning doimiy ravishda ishlab turishi oqibatida butun planshetning ishlashi sekinlashi mumkin."</string>
<string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Ilova tizim qayta yoqilganidan so‘ng o‘zini ishga tushirishi mumkin. Bu telefonning yonish vaqtini uzaytirishi va doimiy ishlab turivchi ilova tufayli uning tezkor ishlashini kamaytirishi mumkin."</string>
<string name="permlab_broadcastSticky" msgid="7919126372606881614">"xabarlarni keyinchalik saqlash sharti bilan yuborish"</string>
- <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"Ilovaga uzatish tugagandan keyin ham qoladigan yopishqoq uzatishlarni jo‘natishga ruxsat beradi. Bu uzatishdan juda ko‘p foydalanish ko‘p xotiradan foydalanishga olib keladi va natijada planshet sekin yoki beqaror ishlashi mumkin."</string>
- <string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"Ilovaga efir tugagandan so‘ng ham saqlanib qoladigan turg‘un translatsiyalarni uzatish huquqini beradi. Undan ortiqcha foydalanish televizoringizni sekinlatishi yoki ko‘p xotira sarflaydigan qilib qo‘yishi mumkin."</string>
- <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Ilovaga uzatish tugagandan keyin ham qoladigan yopishqoq uzatishlarni jo‘natishga ruxsat beradi. Bu uzatishdan juda ko‘p foydalanish ko‘p xotiradan foydalanishga olib keladi va natijada telefon sekin yoki beqaror ishlashi mumkin."</string>
+ <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"Ilova yuborilganidan keyin o‘chib ketmaydigan muddatsiz tarqatma xabarlarni yuborishi mumkin. Ulardan noto‘g‘ri maqsadda foydalanish qurilmaning ishlashini sekinlatishi yoki xotiraga haddan ziyod yuklanish tushishi oqibatida qurilma ishdan chiqishi mumkin."</string>
+ <string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"Ilova yuborilganidan keyin o‘chib ketmaydigan muddatsiz tarqatma xabarlarni yuborishi mumkin. Ulardan noto‘g‘ri maqsadda foydalanish qurilmaning ishlashini sekinlatishi yoki xotiraga haddan ziyod yuklanish tushishi oqibatida qurilma ishdan chiqishi mumkin."</string>
+ <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Ilova yuborilganidan keyin o‘chib ketmaydigan muddatsiz tarqatma xabarlarni yuborishi mumkin. Ulardan noto‘g‘ri maqsadda foydalanish qurilmaning ishlashini sekinlatishi yoki xotiraga haddan ziyod yuklanish tushishi oqibatida qurilma ishdan chiqishi mumkin."</string>
<string name="permlab_readContacts" msgid="8348481131899886131">"kontaktlaringizni ko‘rish"</string>
<string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Ilovaga planshetingizda saqlangan kontaktlar ma’lumotlarini, shuningdek, ba‘zi shaxslarga qilgan qo‘ng‘iroqlar muntazamligi, ularga yozgan e-pochta xabarlari yoki boshqa xabar almashish yo‘llari orqali xabarlashganingiz haqidagi ma’lumotlarni o‘qishga ruxsat beradi. Ushbu ruxsat ilovalarga aloqa ma’lumotlaringizni saqlash uchun ruxsat beradi va zararli ilovalar sizga bildirmasdan kontaktlar ma’lumotlaringizni boshqalarga ulashishi mumkin."</string>
<string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"Ilovaga televizoringizda saqlanayotgan kontaktlar haqidagi ma’lumotlarni, jumladan, muayyan shaxslar bilan qo‘ng‘iroqlashish, e-pochta orqali xabarlashish yoki muloqot qilish oralig‘i haqidagi ma’lumotlarni o‘qish huquqini beradi. Ushbu ruxsatnoma ilovalarga kontaktlaringiz haqidagi ma’lumotlarni saqlash huquqini berib, zararli ilovalar uning yordamida kontakt ma’lumotlarini sizdan beruxsat boshqalarga ulashishi mumkin."</string>
@@ -486,7 +486,7 @@
<string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"tarmoq siyosatini boshqarish"</string>
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Ilova tarmoq siyosatini boshqarishi va alohida ilovalar uchun qoidalarni o‘rnatishi mumkin."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"tarmoqdan foydalanishni hisoblashni o‘zgartirish"</string>
- <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ilovaga ilovalarga nisbadan hisoblanadigan tarmoqdan foydalanish ma’lumotlarini o‘zgartirishga ruxsat beradi. Oddiy ilovalar tomonidan foydalanilmaydi."</string>
+ <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ilova turli dasturlar tomonidan ishlatiladigan tarmoq resurslari hisob-kitobini o‘zgartirishi mumkin. Bu ruxsat oddiy ilovalar uchun talab qilinmaydi."</string>
<string name="permlab_accessNotifications" msgid="7673416487873432268">"ruxsat bildirishnomalari"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Dasturga bildirishnomalar va boshqa dasturlar jo‘natgan xabarlarni qabul qilish, ko‘rib chiqish hamda tozalash imkonini beradi."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bildirishnomani tinglash xizmatiga bog‘lash"</string>
@@ -526,7 +526,7 @@
<string name="policydesc_resetPassword" msgid="1278323891710619128">"Ekran qulfini o‘zgartiradi."</string>
<string name="policylab_forceLock" msgid="2274085384704248431">"Ekranni qulflash"</string>
<string name="policydesc_forceLock" msgid="1141797588403827138">"Ekranning qachon va qanday qulflanishini boshqaradi."</string>
- <string name="policylab_wipeData" msgid="3910545446758639713">"Barcha ma’lumotlarni tozalash"</string>
+ <string name="policylab_wipeData" msgid="3910545446758639713">"Barcha ma’lumotlarni o‘chirib tashlash"</string>
<string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Planshetdagi barcha ma’lumotlarni ogohlantirishsiz zavod sozlamalarini tiklash orqali o‘chirib tashlaydi."</string>
<string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Zavod sozlamalarini tiklaydi va televizordagi barcha ma’lumotlarni ogohlantirishsiz o‘chirib tashlaydi."</string>
<string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Telefondagi barcha ma’lumotlarni ogohlantirishsiz zavod sozlamalarini tiklash orqali o‘chirib tashlaydi."</string>
@@ -537,7 +537,7 @@
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Qurilmaga global proksi o‘rnatish"</string>
<string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Qoida faollashtirilgan vaqtda ishlatiladigan qurilmaning global proksi-serverini o‘rnatadi. Faqat qurilma egasi global proksi-serverini o‘rnatishi mumkin."</string>
<string name="policylab_expirePassword" msgid="5610055012328825874">"Parol muddatini o‘rnatish"</string>
- <string name="policydesc_expirePassword" msgid="5367525762204416046">"Ekran qulfi paroli, PIN kodi yoki chizmali paroli o‘zgartiriladigan muddatni o‘zgartiradi."</string>
+ <string name="policydesc_expirePassword" msgid="5367525762204416046">"Ekran qulfi paroli, PIN kodi yoki grafik kaliti o‘zgartiriladigan muddatni o‘zgartiradi."</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Xotirani kodlashni o‘rnatish"</string>
<string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Zaxiralangan ilovalar ma‘lumotlarini kodlashni talab qiladi."</string>
<string name="policylab_disableCamera" msgid="6395301023152297826">"Kameralarni o‘chirish"</string>
@@ -672,7 +672,7 @@
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ekran qulflangan."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Qulfdan chiqarish yoki favqulodda qo‘ng‘iroqni amalga oshirish uchun \"Menyu\"ni bosing."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Qulfni ochish uchun \"Menyu\"ga bosing."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Qulfni ochish uchun namuna ustiga chizing"</string>
+ <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Qulfni ochish uchun grafik kalitni chizing"</string>
<string name="lockscreen_emergency_call" msgid="5298642613417801888">"Favqulodda chaqiruv"</string>
<string name="lockscreen_return_to_call" msgid="5244259785500040021">"Qo‘ng‘iroqni qaytarish"</string>
<string name="lockscreen_pattern_correct" msgid="9039008650362261237">"To‘g‘ri!"</string>
@@ -700,12 +700,12 @@
<string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Foydalanuvchi qo‘llanmasiga qarang yoki Abonentlarni qo‘llab-quvvatlash markaziga murojaat qiling."</string>
<string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM karta qulflangan."</string>
<string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM karta qulfdan chiqarilmoqda…"</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Siz chizmali kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> soniyadan so‘ng qayta urining."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Siz grafik kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> soniyadan so‘ng qayta urining."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Siz parolni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> soniyadan so‘ng qayta urining."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Siz PIN-kodni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> soniyadan so‘ng qayta urining."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Siz chizmali kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. Telefon qulfini ochish uchun yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta noto‘g‘ri urinish qilsangiz, sizdan Google hisobingizga kirish talab qilinadi. \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan so‘ng qayta urining."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Siz chizmali kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. Agar uni yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta noto‘g‘ri kiritsangiz, televizoringizni qulfdan chiqarish uchun Google hisobingizga kirish talab qilinadi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan so‘ng qaytadan urining."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Siz chizmali kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. Telefon qulfini ochish uchun yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta noto‘g‘ri urinish qilsangiz, sizdan Google hisobingizga kirish talab qilinadi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan so‘ng qayta urining."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Siz grafik kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. Telefon qulfini ochish uchun yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta noto‘g‘ri urinish qilsangiz, sizdan Google hisobingizga kirish talab qilinadi. \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan so‘ng qayta urining."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Siz grafik kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. Agar uni yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta noto‘g‘ri kiritsangiz, televizoringizni qulfdan chiqarish uchun Google hisobingizga kirish talab qilinadi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan so‘ng qaytadan urining."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Siz grafik kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. Telefon qulfini ochish uchun yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta noto‘g‘ri urinish qilsangiz, sizdan Google hisobingizga kirish talab qilinadi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan so‘ng qayta urining."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Planshet qulfini <xliff:g id="NUMBER_0">%1$d</xliff:g> marta ochishga urinib ko‘rdingiz. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishlardan so‘ng, planshet ishlab chiqarilgan holatiga tiklanadi va barcha foydalanuvchi ma’lumotlari yo‘qoladi."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"Siz televizorni qulfdan chiqarish parolini <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. Agar uni yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta noto‘g‘ri kiritsangiz, televizoringizda zavod sozlamalari qayta tiklanadi hamda undagi barcha ma’lumotlaringiz o‘chib ketadi."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Telefon qulfini <xliff:g id="NUMBER_0">%1$d</xliff:g> marta ochishga urinib ko‘rdingiz. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishlardan so‘ng, telefon ishlab chiqarilgan holatiga tiklanadi va barcha foydalanuvchi ma’lumotlari yo‘qoladi."</string>
@@ -713,9 +713,9 @@
<string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"Siz televizorni qulfdan chiqarish parolini <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri kiritdingiz. Endi, televizoringizda zavod sozlamalari qayta tiklanadi."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Telefon qulfini <xliff:g id="NUMBER">%d</xliff:g> marta ochishga urinib ko‘rdingiz. Telefon hozir ishlab chiqarilgan holatiga tiklanadi."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g> soniyadan so‘ng qayta urinib ko‘ring."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Chizma namunasi yodingizdan chiqdimi?"</string>
+ <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Grafik kalit esingizdan chiqdimi?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Qulfni ochish hisobi"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Chizmali parolni ochishga juda ko‘p urinildi"</string>
+ <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Grafik kalit juda ko‘p marta chizildi"</string>
<string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Qulfni ochish uchun Google hisobingiz bilan kiring."</string>
<string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Foydalanuvchi nomi (e-pochta)"</string>
<string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Parol"</string>
@@ -726,12 +726,12 @@
<string name="lockscreen_unlock_label" msgid="737440483220667054">"Qulfdan chiqarish"</string>
<string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Ovozni yoqish"</string>
<string name="lockscreen_sound_off_label" msgid="996822825154319026">"Ovozni o‘chirish"</string>
- <string name="lockscreen_access_pattern_start" msgid="3941045502933142847">"Chizma namunasi ishga tushirildi"</string>
- <string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Chizma namunasi tozalandi"</string>
+ <string name="lockscreen_access_pattern_start" msgid="3941045502933142847">"Grafik kalitni chizish boshlandi"</string>
+ <string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Grafik kalit tozalandi"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Katak qo‘shildi"</string>
<string name="lockscreen_access_pattern_cell_added_verbose" msgid="7264580781744026939">"<xliff:g id="CELL_INDEX">%1$s</xliff:g> katak qo‘shildi"</string>
- <string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Chizma namunasi tugatildi"</string>
- <string name="lockscreen_access_pattern_area" msgid="400813207572953209">"Chizmali kalit hududi."</string>
+ <string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Grafik kalitni chizish tugallandi"</string>
+ <string name="lockscreen_access_pattern_area" msgid="400813207572953209">"Grafik kalit chiziladigan hudud."</string>
<string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Vidjet %2$d / %3$d."</string>
<string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Vidjet qo‘shish."</string>
<string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Bo‘sh"</string>
@@ -747,11 +747,11 @@
<string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> vidjeti o‘chirildi."</string>
<string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Qulfni ochish maydonini kengaytirish."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Qulfni silab ochish"</string>
- <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Chizmali qulfni ochish."</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Grafik kalit bilan ochish."</string>
<string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Qulfni yuzni tanitib ochish"</string>
<string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Pin qulfini ochish."</string>
<string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Parolli qulfni ochish."</string>
- <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Chizmali qulf maydoni."</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Grafik kalit chiziladigan hudud."</string>
<string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Maydonni silang"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Masshtab"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Doimo ko‘rsatish"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Uni Tizim sozlamalari > Ilovalar > Yuklab olingan menyusidan qayta yoqing."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” ilovasi joriy ekran o‘lchami sozlamalariga mos kelmasligi va noto‘g‘ri ishlashi mumkin."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Har doim ko‘rsatilsin"</string>
<string name="smv_application" msgid="3307209192155442829">"“<xliff:g id="APPLICATION">%1$s</xliff:g>” ilovasi (jarayaon: <xliff:g id="PROCESS">%2$s</xliff:g>) o‘zining StrictMode qoidasini buzdi."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> jarayoni o‘zining o‘zi-bajaruvchi StrictMode siyosatini buzdi."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android yangilanmoqda…"</string>
@@ -1151,7 +1153,7 @@
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"nomzodlar"</u></string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> tayyorlanmoqda"</string>
- <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Xatolar tekshirilmoqda"</string>
+ <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Xatolar qidirilmoqda"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Yangi <xliff:g id="NAME">%s</xliff:g> kartasi aniqlandi"</string>
<string name="ext_media_ready_notification_message" msgid="4083398150380114462">"Rasm va boshqa fayllarni o‘tkazish"</string>
<string name="ext_media_unmountable_notification_title" msgid="8295123366236989588">"“<xliff:g id="NAME">%s</xliff:g>” buzilgan"</string>
@@ -1368,7 +1370,7 @@
<string name="media_route_chooser_searching" msgid="4776236202610828706">"Qurilmalar izlanmoqda..."</string>
<string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Sozlamalar"</string>
<string name="media_route_controller_disconnect" msgid="8966120286374158649">"Uzish"</string>
- <string name="media_route_status_scanning" msgid="7279908761758293783">"Tekshirilmoqda..."</string>
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"Qidirilmoqda..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Ulanmoqda..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Mavjud"</string>
<string name="media_route_status_not_available" msgid="6739899962681886401">"Mavjud emas"</string>
@@ -1378,8 +1380,8 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Tasvir uzatish #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", xavfsiz"</string>
- <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Chizmali parol unutilgan"</string>
- <string name="kg_wrong_pattern" msgid="1850806070801358830">"Chizmali kalit noto‘g‘ri"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Grafik kalit esimdan chiqdi"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"Grafik kalit noto‘g‘ri"</string>
<string name="kg_wrong_password" msgid="2333281762128113157">"Parol noto‘g‘ri"</string>
<string name="kg_wrong_pin" msgid="1131306510833563801">"PIN-kod noto‘g‘ri"</string>
<string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%1$d</xliff:g> soniyadan so‘ng qayta urinib ko‘ring."</string>
@@ -1396,7 +1398,7 @@
<string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"PUK kod 8 ta raqam bo‘lishi shart."</string>
<string name="kg_invalid_puk" msgid="3638289409676051243">"To‘g‘ri PUK kodni qayta kiriting. Qayta-qayta urinishlar SIM kartani butunlay o‘chirib qo‘yadi."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-kod mos kelmadi"</string>
- <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Chizmali parolni ochishga juda ko‘p urinildi"</string>
+ <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Grafik kalit juda ko‘p marta chizildi"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Qulfni ochish uchun Google hisobingiz bilan kiring."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"Foydalanuvchi nomi (e-pochta)"</string>
<string name="kg_login_password_hint" msgid="9057289103827298549">"Parol"</string>
@@ -1406,16 +1408,16 @@
<string name="kg_login_checking_password" msgid="1052685197710252395">"Hisob tekshirilmoqda…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Siz PIN-kodni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> soniyadan so‘ng qayta urinib ko‘ring."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Siz parolni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> soniyadan so‘ng qayta urinib ko‘ring."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Siz chizmali kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> soniyadan so‘ng qayta urinib ko‘ring."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Siz grafik kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> soniyadan so‘ng qayta urinib ko‘ring."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Siz planshet qulfini ochish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta muvaffaqiyatsiz urindingiz. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishlardan so‘ng planshetning zavod sozlamalari tiklanadi va barcha foydalanuvchi ma’lumotlari o‘chiriladi."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="5621231220154419413">"Siz televizorni qulfdan chiqarish parolini <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. Agar uni yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta noto‘g‘ri kiritsangiz, televizoringizda zavod sozlamalari qayta tiklanadi hamda undagi barcha ma’lumotlaringiz o‘chib ketadi."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Siz telefon qulfini ochish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta muvaffaqiyatsiz urindingiz. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishlardan so‘ng telefonning zavod sozlamalari tiklanadi va barcha foydalanuvchi ma’lumotlari o‘chiriladi."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Planshet qulfini ochish uchun <xliff:g id="NUMBER">%d</xliff:g> marta muvaffaqiyatsiz urinib ko‘rdingiz. Planshetning hozir zavod sozlamari tiklanadi."</string>
<string name="kg_failed_attempts_now_wiping" product="tv" msgid="4987878286750741463">"Siz televizorni qulfdan chiqarish parolini <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri kiritdingiz. Endi, televizoringizda zavod sozlamalari qayta tiklanadi."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Telefon qulfini ochish uchun <xliff:g id="NUMBER">%d</xliff:g> marta muvaffaqiyatsiz urinib ko‘rdingiz. Telefonning hozir zavod sozlamari tiklanadi."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Siz chizmali kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan so‘ng, sizdan e-pochtangizdan foydalanib, planshet qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan so‘ng yana urinib ko‘ring."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Siz chizmali kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. Agar uni yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta noto‘g‘ri kiritsangiz, televizoringizni qulfdan chiqarish uchun sizda e-pochta hisobingizga kirish talab qilinadi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan so‘ng qaytadan urining."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Siz chizmali kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri chizdingiz. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan so‘ng, sizdan e-pochtangizdan foydalanib, telefon qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan so‘ng yana urinib ko‘ring."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Siz grafik kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan so‘ng, sizdan e-pochtangizdan foydalanib, planshet qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan so‘ng yana urinib ko‘ring."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Siz grafik kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. Agar uni yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta noto‘g‘ri kiritsangiz, televizoringizni qulfdan chiqarish uchun sizda e-pochta hisobingizga kirish talab qilinadi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan so‘ng qaytadan urining."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Siz grafik kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri chizdingiz. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan so‘ng, sizdan e-pochtangizdan foydalanib, telefon qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan so‘ng yana urinib ko‘ring."</string>
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"O‘chirish"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Ovoz balandligi tavsiya etilgan darajadan ham yuqori ko‘tarilsinmi?\n\nUzoq vaqt davomida baland ovozda tinglash eshitish qobiliyatingizga salbiy ta’sir ko‘rsatishi mumkin."</string>
@@ -1550,7 +1552,7 @@
<string name="lock_to_app_start" msgid="6643342070839862795">"Ekran qadab qo‘yildi"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Ekran bo‘shatildi"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Yechishda PIN-kod so‘ralsin"</string>
- <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Bo‘shatishdan oldin chizmali parol so‘ralsin"</string>
+ <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Yechishdan oldin grafik kalit so‘ralsin"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Bo‘shatishdan oldin parol so‘ralsin"</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Administratoringiz tomonidan o‘rnatilgan"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Administratoringiz tomonidan yangilandi"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index a2a3143..7888e42 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Tỷ lệ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Luôn hiển thị"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Bật lại chế độ này trong cài đặt Hệ thống > Ứng dụng > Đã tải xuống."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> không hỗ trợ cài đặt kích thước Màn hình hiện tại và có thể hoạt động không như mong đợi."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Luôn hiển thị"</string>
<string name="smv_application" msgid="3307209192155442829">"Ứng dụng <xliff:g id="APPLICATION">%1$s</xliff:g> (quá trình <xliff:g id="PROCESS">%2$s</xliff:g>) đã vi phạm chính sách StrictMode tự thi hành của mình."</string>
<string name="smv_process" msgid="5120397012047462446">"Quá trình <xliff:g id="PROCESS">%1$s</xliff:g> đã vi phạm chính sách StrictMode tự thi hành của mình."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android đang nâng cấp..."</string>
diff --git a/core/res/res/values-watch/config_material.xml b/core/res/res/values-watch/config_material.xml
index 951c088..81b53e7 100644
--- a/core/res/res/values-watch/config_material.xml
+++ b/core/res/res/values-watch/config_material.xml
@@ -27,9 +27,6 @@
<!-- Use micro alert controller -->
<integer name="config_alertDialogController">1</integer>
- <!-- Dialog windows in watch should occupy the whole screen and not be floating. -->
- <bool name="config_dialogWindowIsFloating">false</bool>
-
<!-- Always overscan by default to ensure onApplyWindowInsets will always be called. -->
<bool name="config_windowOverscanByDefault">true</bool>
diff --git a/core/res/res/values-watch/themes_material.xml b/core/res/res/values-watch/themes_material.xml
index d92a947..4ae4367 100644
--- a/core/res/res/values-watch/themes_material.xml
+++ b/core/res/res/values-watch/themes_material.xml
@@ -38,4 +38,25 @@
<item name="imeFullscreenBackground">?colorBackground</item>
<item name="imeExtractEnterAnimation">@anim/input_method_extract_enter</item>
</style>
+
+ <!-- Override behaviour to set the theme colours for dialogs, keep them the same. -->
+ <style name="ThemeOverlay.Material.Dialog" parent="ThemeOverlay.Material.BaseDialog">
+ <item name="windowIsFloating">false</item>
+ </style>
+
+ <!-- Force the background and floating colours to be the default colours. -->
+ <style name="Theme.Material.Dialog" parent="Theme.Material.BaseDialog">
+ <item name="colorBackground">@color/background_material_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_material_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_dark</item>
+ <item name="windowIsFloating">false</item>
+ </style>
+
+ <!-- Force the background and floating colours to be the default colours. -->
+ <style name="Theme.Material.Light.Dialog" parent="Theme.Material.Light.BaseDialog">
+ <item name="colorBackground">@color/background_material_light</item>
+ <item name="colorBackgroundFloating">@color/background_floating_material_light</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_light</item>
+ <item name="windowIsFloating">false</item>
+ </style>
</resources>
diff --git a/core/res/res/values-zh-rCN-watch/styles_material.xml b/core/res/res/values-zh-rCN-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-zh-rCN-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?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.
+ -->
+
+<!--
+===============================================================
+ 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 styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index c7462f1..2169981 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"缩放"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"始终显示"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"在“系统设置”>“应用”>“已下载”中重新启用此模式。"</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g>不支持当前的显示大小设置,因此可能无法正常显示。"</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"一律显示"</string>
<string name="smv_application" msgid="3307209192155442829">"“<xliff:g id="APPLICATION">%1$s</xliff:g>”应用(<xliff:g id="PROCESS">%2$s</xliff:g> 进程)违反了自我强制执行的严格模式 (StrictMode) 政策。"</string>
<string name="smv_process" msgid="5120397012047462446">"进程 <xliff:g id="PROCESS">%1$s</xliff:g> 违反了自我强制执行的严格模式 (StrictMode) 政策。"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android正在升级..."</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index a791ccd..520a0e8 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"比例"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"永遠顯示"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"前往 [系統設定] > [應用程式] > [下載] 重新啟用這個模式。"</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援目前的「螢幕」尺寸設定,畫面可能無法如預期顯示。"</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"永遠顯示"</string>
<string name="smv_application" msgid="3307209192155442829">"應用程式 <xliff:g id="APPLICATION">%1$s</xliff:g> (處理程序 <xliff:g id="PROCESS">%2$s</xliff:g>) 已違反其自行強制實施的嚴格模式 (StrictMode) 政策。"</string>
<string name="smv_process" msgid="5120397012047462446">"處理程序 <xliff:g id="PROCESS">%1$s</xliff:g> 已違反其自行強制實施的嚴格模式 (StrictMode) 政策。"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"正在升級 Android..."</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index ec7b2fdc..4a61cd2 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"比例"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"一律顯示"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"前往 [系統設定] > [應用程式] > [下載] 重新啟用這個模式。"</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援目前的顯示大小設定,可能會發生非預期的行為。"</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"一律顯示"</string>
<string name="smv_application" msgid="3307209192155442829">"應用程式 <xliff:g id="APPLICATION">%1$s</xliff:g> (處理程序 <xliff:g id="PROCESS">%2$s</xliff:g>) 已違反其自行強制實施的嚴格模式 (StrictMode) 政策。"</string>
<string name="smv_process" msgid="5120397012047462446">"處理程序 <xliff:g id="PROCESS">%1$s</xliff:g> 已違反其自行強制實施的嚴格模式 (StrictMode) 政策。"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"正在升級 Android…"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 6f5a6ea..c278a65 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1015,6 +1015,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Isilinganisi"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Bonisa njalo"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Yenza kuphinde kusebenze kuzilungiselelo Zesistimue > Izinhlelo zokusebenza > Okulayishiwe."</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayisekeli isilungiselelo sosayizi sokubonisa samanje futhi ingasebenza ngokungalindelekile."</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"Bonisa njalo"</string>
<string name="smv_application" msgid="3307209192155442829">"Inqubo <xliff:g id="APPLICATION">%1$s</xliff:g> (yohlelo <xliff:g id="PROCESS">%2$s</xliff:g>) iphule inqubomgomo oziphoqelela yona Yemodi Ebukhali."</string>
<string name="smv_process" msgid="5120397012047462446">"Inqubo <xliff:g id="PROCESS">%1$s</xliff:g> yephule inqubomgomo yokuziphoqelela Yemodi Ebukhali."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"I-Android ifaka ezakamuva..."</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index d0c6a8e..a70c4fd 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1048,6 +1048,9 @@
the status bar (via statusBarColor) and navigation bar (via navigationBarColor). -->
<attr name="colorPrimaryDark" format="color" />
+ <!-- The secondary branding color for the app. -->
+ <attr name="colorSecondary" format="color" />
+
<!-- Bright complement to the primary branding color. By default, this is the color applied
to framework controls (via colorControlActivated). -->
<attr name="colorAccent" format="color" />
@@ -1832,10 +1835,10 @@
<enum name="KEYCODE_CUT" value="277" />
<enum name="KEYCODE_COPY" value="278" />
<enum name="KEYCODE_PASTE" value="279" />
- <enum name="KEYCODE_FP_NAV_UP" value="280" />
- <enum name="KEYCODE_FP_NAV_DOWN" value="281" />
- <enum name="KEYCODE_FP_NAV_LEFT" value="282" />
- <enum name="KEYCODE_FP_NAV_RIGHT" value="283" />
+ <enum name="KEYCODE_SYSTEM_NAVIGATION_UP" value="280" />
+ <enum name="KEYCODE_SYSTEM_NAVIGATION_DOWN" value="281" />
+ <enum name="KEYCODE_SYSTEM_NAVIGATION_LEFT" value="282" />
+ <enum name="KEYCODE_SYSTEM_NAVIGATION_RIGHT" value="283" />
</attr>
<!-- ***************************************************************** -->
@@ -7350,7 +7353,11 @@
<!-- Title of the uri that specifies a link for further context of this wallpaper, e.g. Explore collection. -->
<attr name="contextDescription" format="reference" />
- <!-- Whether to show any metadata when previewing the wallpaper. -->
+ <!-- Whether to show any metadata when previewing the wallpaper. If this value is
+ set to true, any component that shows a preview of this live wallpaper should also show
+ accompanying information like the title, the description, the author and the context
+ description of this wallpaper so the user gets to know further information about this
+ wallpaper. -->
<attr name="showMetadataInPreview" format="boolean" />
</declare-styleable>
@@ -8251,12 +8258,13 @@
<declare-styleable name="Shortcut">
<attr name="shortcutId" format="string" />
<attr name="enabled" />
- <attr name="shortcutIcon" format="reference" />
+ <attr name="icon" />
<attr name="shortcutShortLabel" format="reference" />
<attr name="shortcutLongLabel" format="reference" />
<attr name="shortcutDisabledMessage" format="reference" />
- <attr name="shortcutCategories" format="string" />
- <attr name="shortcutIntentAction" format="string" />
- <attr name="shortcutIntentData" format="string" />
+ </declare-styleable>
+
+ <declare-styleable name="ShortcutCategories">
+ <attr name="name" />
</declare-styleable>
</resources>
diff --git a/core/res/res/values/colors_device_defaults.xml b/core/res/res/values/colors_device_defaults.xml
new file mode 100644
index 0000000..5518de2
--- /dev/null
+++ b/core/res/res/values/colors_device_defaults.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<!-- Colors specific to DeviceDefault themes. These are mostly pass-throughs to enable
+ overlaying new theme colors. -->
+<resources>
+ <color name="primary_device_default_dark">@color/primary_material_dark</color>
+ <color name="primary_device_default_light">@color/primary_material_light</color>
+ <color name="primary_device_default_settings">@color/primary_material_settings</color>
+ <color name="primary_dark_device_default_dark">@color/primary_dark_material_dark</color>
+ <color name="primary_dark_device_default_light">@color/primary_dark_material_light</color>
+ <color name="primary_dark_device_default_settings">@color/primary_dark_material_settings</color>
+
+ <color name="secondary_device_default_settings">@color/secondary_material_settings</color>
+ <color name="tertiary_device_default_settings">@color/tertiary_material_settings</color>
+
+ <color name="accent_device_default_light">@color/accent_material_light</color>
+ <color name="accent_device_default_dark">@color/accent_material_dark</color>
+</resources>
\ No newline at end of file
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index c8ca116..2ac4092a5 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -26,9 +26,14 @@
<color name="primary_material_dark">@color/material_grey_900</color>
<color name="primary_material_light">@color/material_grey_100</color>
+ <color name="primary_material_settings">@color/material_blue_grey_900</color>
<color name="primary_dark_material_dark">@color/black</color>
<color name="primary_dark_material_light">@color/material_grey_600</color>
<color name="primary_dark_material_light_light_status_bar">@color/material_grey_300</color>
+ <color name="primary_dark_material_settings">@color/material_blue_grey_950</color>
+
+ <color name="secondary_material_settings">@color/material_blue_grey_800</color>
+ <color name="tertiary_material_settings">@color/material_blue_grey_700</color>
<color name="accent_material_light">@color/material_deep_teal_500</color>
<color name="accent_material_dark">@color/material_deep_teal_200</color>
@@ -80,6 +85,7 @@
<color name="material_deep_teal_300">#ff4db6ac</color>
<color name="material_deep_teal_500">#ff009688</color>
+ <color name="material_blue_grey_700">#ff455a64</color>
<color name="material_blue_grey_800">#ff37474f</color>
<color name="material_blue_grey_900">#ff263238</color>
<color name="material_blue_grey_950">#ff21272b</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6b4fb29..7f52b48 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2461,6 +2461,10 @@
<!-- True if the device supports Sustained Performance Mode-->
<bool name="config_sustainedPerformanceModeSupported">false</bool>
+ <!-- File used to enable the double touch gesture.
+ TODO: move to input HAL once ready. -->
+ <string name="config_doubleTouchGestureEnableFile"></string>
+
<!-- Controls how we deal with externally connected physical keyboards.
0 - When using this device, it is not clear for users to recognize when the physical
keyboard is (should be) connected and when it is (should be) disconnected. Most of
diff --git a/core/res/res/values/config_material.xml b/core/res/res/values/config_material.xml
index f62678a..a37be83 100644
--- a/core/res/res/values/config_material.xml
+++ b/core/res/res/values/config_material.xml
@@ -29,9 +29,6 @@
<!-- The alert controller to use for alert dialogs. -->
<integer name="config_alertDialogController">0</integer>
- <!-- True if dialog windows are floating. -->
- <bool name="config_dialogWindowIsFloating">true</bool>
-
<!-- True if windowOverscan should be on by default. -->
<bool name="config_windowOverscanByDefault">false</bool>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index da31767..9ccd39f 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2733,17 +2733,14 @@
=============================================================== -->
<eat-comment />
<public type="attr" name="shortcutId" />
- <public type="attr" name="shortcutIcon" />
<public type="attr" name="shortcutShortLabel" />
<public type="attr" name="shortcutLongLabel" />
<public type="attr" name="shortcutDisabledMessage" />
- <public type="attr" name="shortcutCategories" />
- <public type="attr" name="shortcutIntentAction" />
- <public type="attr" name="shortcutIntentData" />
<public type="attr" name="roundIcon" />
<public type="attr" name="contextUri" />
<public type="attr" name="contextDescription" />
<public type="attr" name="showMetadataInPreview" />
+ <public type="attr" name="colorSecondary" />
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 5db562d..ae2a9e4 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2768,6 +2768,11 @@
<!-- [CHAR LIMIT=200] Compat mode dialog: hint to re-enable compat mode dialog. -->
<string name="screen_compat_mode_hint">Re-enable this in System settings > Apps > Downloaded.</string>
+ <!-- [CHAR LIMIT=200] Unsupported display size dialog: message. Refers to "Display size" setting. -->
+ <string name="unsupported_display_size_message"><xliff:g id="app_name">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly.</string>
+ <!-- [CHAR LIMIT=50] Unsupported display size dialog: check box label. -->
+ <string name="unsupported_display_size_show">Always show</string>
+
<!-- Text of the alert that is displayed when an application has violated StrictMode. -->
<string name="smv_application">The app <xliff:g id="application">%1$s</xliff:g>
(process <xliff:g id="process">%2$s</xliff:g>) has violated its self-enforced StrictMode policy.</string>
@@ -4367,15 +4372,21 @@
<string name="negative_duration">\u2212<xliff:g id="time" example="1:14">%1$s</xliff:g></string>
<!-- Title of notification to start a new demo session when device is in retail mode [CHAR LIMIT=NONE] -->
- <string name="reset_retail_demo_mode_title">Restart Session</string>
+ <string name="reset_retail_demo_mode_title">Reset device?</string>
<!-- Text of notification to start a new demo session when device is in retail mode [CHAR LIMIT=NONE] -->
- <string name="reset_retail_demo_mode_text">Tap to start a new demo session</string>
+ <string name="reset_retail_demo_mode_text">Tap to reset device</string>
<!-- Text of dialog shown when starting a demo user for the first time [CHAR LIMIT=40] -->
- <string name="demo_starting_message">Starting demo</string>
+ <string name="demo_starting_message">Starting demo\u2026</string>
<!-- Text of dialog shown when starting a new demo user in retail demo mode [CHAR LIMIT=40] -->
- <string name="demo_restarting_message">Restarting session</string>
-
-
+ <string name="demo_restarting_message">Resetting device\u2026</string>
+ <!-- Title of the dialog shown when user inactivity times out in retail demo mode [CHAR LIMIT=40] -->
+ <string name="demo_user_inactivity_timeout_title">Reset device?</string>
+ <!-- Warning message shown when user inactivity times out in retail demo mode [CHAR LIMIT=none] -->
+ <string name="demo_user_inactivity_timeout_countdown">You\'ll lose any changes and the demo will start again in <xliff:g id="timeout" example="9">%1$s</xliff:g> seconds\u2026</string>
+ <!-- Text of button to allow user to abort countdown and continue current session in retail demo mode [CHAR LIMIT=40] -->
+ <string name="demo_user_inactivity_timeout_left_button">Cancel</string>
+ <!-- Text of button to allow user to abort countdown and immediately start another session in retail demo mode [CHAR LIMIT=40] -->
+ <string name="demo_user_inactivity_timeout_right_button">Reset now</string>
<!-- Title of notification shown when device has been forced to safe mode after a security compromise. -->
<string name="audit_safemode_notification">Factory reset to use this device without restrictions</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 273086d..762cf31 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1410,7 +1410,7 @@
<item name="paddingEnd">?attr/dialogPreferredPadding</item>
<item name="background">?attr/selectableItemBackground</item>
<item name="drawablePadding">32dp</item>
- <item name="drawableTint">@color/accent_material_light</item>
+ <item name="drawableTint">?android:attr/colorAccent</item>
<item name="drawableTintMode">src_atop</item>
</style>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6e937ff..6b7d32d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1892,6 +1892,10 @@
<java-symbol type="string" name="audit_safemode_notification_details" />
<java-symbol type="string" name="reset_retail_demo_mode_title" />
<java-symbol type="string" name="reset_retail_demo_mode_text" />
+ <java-symbol type="string" name="demo_user_inactivity_timeout_title" />
+ <java-symbol type="string" name="demo_user_inactivity_timeout_countdown" />
+ <java-symbol type="string" name="demo_user_inactivity_timeout_left_button" />
+ <java-symbol type="string" name="demo_user_inactivity_timeout_right_button" />
<java-symbol type="layout" name="resolver_list" />
<java-symbol type="id" name="resolver_list" />
@@ -2614,6 +2618,8 @@
<!-- Pinner Service -->
<java-symbol type="array" name="config_defaultPinnerServiceFiles" />
+ <java-symbol type="string" name="config_doubleTouchGestureEnableFile" />
+
<java-symbol type="string" name="suspended_widget_accessibility" />
<!-- Used internally for assistant to launch activity transitions -->
@@ -2623,4 +2629,7 @@
<!-- For System navigation keys -->
<java-symbol type="bool" name="config_supportSystemNavigationKeys" />
+
+ <java-symbol type="layout" name="unsupported_display_size_dialog_content" />
+ <java-symbol type="string" name="unsupported_display_size_message" />
</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 998eea5..92f049d 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -57,6 +57,7 @@
<item name="colorPrimaryDark">@color/legacy_primary_dark</item>
<item name="colorPrimary">@color/legacy_primary</item>
+ <item name="colorSecondary">?attr/colorPrimary</item>
<item name="colorControlActivated">@color/legacy_control_activated</item>
<item name="colorControlNormal">@color/legacy_control_normal</item>
<item name="colorControlHighlight">@color/legacy_button_pressed</item>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index ea1b626..dd0dac6 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -199,25 +199,50 @@
<item name="mediaRouteButtonStyle">@style/Widget.DeviceDefault.MediaRouteButton</item>
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar -->
- <style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Material.NoActionBar" />
+ <style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Material.NoActionBar">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ </style>
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar. This theme
sets {@link android.R.attr#windowFullscreen} to true. -->
- <style name="Theme.DeviceDefault.NoActionBar.Fullscreen" parent="Theme.Material.NoActionBar.Fullscreen" />
+ <style name="Theme.DeviceDefault.NoActionBar.Fullscreen" parent="Theme.Material.NoActionBar.Fullscreen">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ </style>
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and
extending in to overscan region. This theme
sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
to true. -->
- <style name="Theme.DeviceDefault.NoActionBar.Overscan" parent="Theme.Material.NoActionBar.Overscan" />
+ <style name="Theme.DeviceDefault.NoActionBar.Overscan" parent="Theme.Material.NoActionBar.Overscan">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ </style>
<!-- Variant of {@link #Theme_DeviceDefault} 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.DeviceDefault.NoActionBar.TranslucentDecor" parent="Theme.Material.NoActionBar.TranslucentDecor" />
+ <style name="Theme.DeviceDefault.NoActionBar.TranslucentDecor" parent="Theme.Material.NoActionBar.TranslucentDecor">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ </style>
<!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
floating (not fill the entire screen), and puts a frame around its contents. You can set this
@@ -231,18 +256,38 @@
<item name="textAppearance">@style/TextAppearance.DeviceDefault</item>
<item name="textAppearanceInverse">@style/TextAppearance.DeviceDefault.Inverse</item>
+
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
regular dialog. -->
- <style name="Theme.DeviceDefault.Dialog.MinWidth" parent="Theme.Material.Dialog.MinWidth" />
+ <style name="Theme.DeviceDefault.Dialog.MinWidth" parent="Theme.Material.Dialog.MinWidth">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ </style>
<!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
- <style name="Theme.DeviceDefault.Dialog.NoActionBar" parent="Theme.Material.Dialog.NoActionBar" />
+ <style name="Theme.DeviceDefault.Dialog.NoActionBar" parent="Theme.Material.Dialog.NoActionBar">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ </style>
<!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
for a regular dialog. -->
- <style name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Dialog.NoActionBar.MinWidth" />
+ <style name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Dialog.NoActionBar.MinWidth">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ </style>
<!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
<style name="Theme.DeviceDefault.Dialog.FixedSize">
@@ -262,44 +307,99 @@
<!-- DeviceDefault 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.DeviceDefault.DialogWhenLarge" parent="Theme.Material.DialogWhenLarge" />
+ <style name="Theme.DeviceDefault.DialogWhenLarge" parent="Theme.Material.DialogWhenLarge">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ </style>
<!-- DeviceDefault 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.DeviceDefault.DialogWhenLarge.NoActionBar" parent="Theme.Material.DialogWhenLarge.NoActionBar" />
+ <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar" parent="Theme.Material.DialogWhenLarge.NoActionBar">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ </style>
<!-- DeviceDefault theme for a presentation window on a secondary display. -->
- <style name="Theme.DeviceDefault.Dialog.Presentation" parent="Theme.Material.Dialog.Presentation" />
+ <style name="Theme.DeviceDefault.Dialog.Presentation" parent="Theme.Material.Dialog.Presentation">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ </style>
<!-- DeviceDefault 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.DeviceDefault.Panel" parent="Theme.Material.Panel" />
+ <style name="Theme.DeviceDefault.Panel" parent="Theme.Material.Panel">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ </style>
<!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
behind them. -->
- <style name="Theme.DeviceDefault.Wallpaper" parent="Theme.Material.Wallpaper" />
+ <style name="Theme.DeviceDefault.Wallpaper" parent="Theme.Material.Wallpaper">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ </style>
<!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
behind them and without an action bar. -->
- <style name="Theme.DeviceDefault.Wallpaper.NoTitleBar" parent="Theme.Material.Wallpaper.NoTitleBar" />
+ <style name="Theme.DeviceDefault.Wallpaper.NoTitleBar" parent="Theme.Material.Wallpaper.NoTitleBar">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ </style>
<!-- DeviceDefault style for input methods, which is used by the
{@link android.inputmethodservice.InputMethodService} class.-->
- <style name="Theme.DeviceDefault.InputMethod" parent="Theme.Material.InputMethod" />
+ <style name="Theme.DeviceDefault.InputMethod" parent="Theme.Material.InputMethod">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_light</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
+ </style>
<!-- DeviceDefault style for input methods, which is used by the
{@link android.service.voice.VoiceInteractionSession} class.-->
- <style name="Theme.DeviceDefault.VoiceInteractionSession" parent="Theme.Material.VoiceInteractionSession" >
-
+ <style name="Theme.DeviceDefault.VoiceInteractionSession" parent="Theme.Material.VoiceInteractionSession">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_light</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
</style>
+
<style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Material.Dialog.Alert">
<item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
+
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
</style>
- <style name="Theme.DeviceDefault.SearchBar" parent="Theme.Material.SearchBar" />
- <style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Material.Dialog.NoFrame" />
+ <style name="Theme.DeviceDefault.SearchBar" parent="Theme.Material.SearchBar">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ </style>
+
+ <style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Material.Dialog.NoFrame">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ </style>
<!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style -->
<style name="Theme.DeviceDefault.Light" parent="Theme.Material.Light" >
@@ -447,34 +547,63 @@
<item name="mediaRouteButtonStyle">@style/Widget.DeviceDefault.Light.MediaRouteButton</item>
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_light</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
</style>
<!-- Variant of the DeviceDefault (light) theme that has a solid (opaque) action bar with an
inverse color profile. -->
- <style name="Theme.DeviceDefault.Light.DarkActionBar" parent="Theme.Material.Light.DarkActionBar" />
+ <style name="Theme.DeviceDefault.Light.DarkActionBar" parent="Theme.Material.Light.DarkActionBar">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
+ </style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
- <style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Material.Light.NoActionBar" />
+ <style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Material.Light.NoActionBar">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_light</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
+ </style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar.
This theme sets {@link android.R.attr#windowFullscreen} to true. -->
- <style name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen" parent="Theme.Material.Light.NoActionBar.Fullscreen" />
+ <style name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen" parent="Theme.Material.Light.NoActionBar.Fullscreen">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_light</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
+ </style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar
and extending in to overscan region. This theme
sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
to true. -->
- <style name="Theme.DeviceDefault.Light.NoActionBar.Overscan" parent="Theme.Material.Light.NoActionBar.Overscan" />
+ <style name="Theme.DeviceDefault.Light.NoActionBar.Overscan" parent="Theme.Material.Light.NoActionBar.Overscan">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_light</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
+ </style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} 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.DeviceDefault.Light.NoActionBar.TranslucentDecor" parent="Theme.Material.Light.NoActionBar.TranslucentDecor" />
+ <style name="Theme.DeviceDefault.Light.NoActionBar.TranslucentDecor" parent="Theme.Material.Light.NoActionBar.TranslucentDecor">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_light</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
+ </style>
<!-- DeviceDefault light theme for dialog windows and activities. 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.DeviceDefault.Light.Dialog" parent="Theme.Material.Light.Dialog" >
+ <style name="Theme.DeviceDefault.Light.Dialog" parent="Theme.Material.Light.Dialog">
<item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault.Light</item>
<item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
@@ -483,18 +612,38 @@
<item name="textAppearance">@style/TextAppearance.DeviceDefault</item>
<item name="textAppearanceInverse">@style/TextAppearance.DeviceDefault.Inverse</item>
+
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_light</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} that has a nice minimum width for a
regular dialog. -->
- <style name="Theme.DeviceDefault.Light.Dialog.MinWidth" parent="Theme.Material.Light.Dialog.MinWidth" />
+ <style name="Theme.DeviceDefault.Light.Dialog.MinWidth" parent="Theme.Material.Light.Dialog.MinWidth">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_light</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
+ </style>
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar -->
- <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar" parent="Theme.Material.Light.Dialog.NoActionBar" />
+ <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar" parent="Theme.Material.Light.Dialog.NoActionBar">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_light</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
+ </style>
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum
width for a regular dialog. -->
- <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Light.Dialog.NoActionBar.MinWidth" />
+ <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Light.Dialog.NoActionBar.MinWidth">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_light</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
+ </style>
<!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
<style name="Theme.DeviceDefault.Light.Dialog.FixedSize">
@@ -502,6 +651,11 @@
<item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
<item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
<item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
+
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_light</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
</style>
<!-- Variant of Theme.DeviceDefault.Dialog.NoActionBar that has a fixed size. -->
@@ -510,33 +664,110 @@
<item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
<item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
<item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
+
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_light</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
</style>
<!-- DeviceDefault light 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.DeviceDefault.Light.DialogWhenLarge" parent="Theme.Material.Light.DialogWhenLarge" />
+ <style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="Theme.Material.Light.DialogWhenLarge">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_light</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
+ </style>
<!-- DeviceDefault light 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.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="Theme.Material.Light.DialogWhenLarge.NoActionBar" />
+ <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="Theme.Material.Light.DialogWhenLarge.NoActionBar">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_light</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
+ </style>
<!-- DeviceDefault light theme for a presentation window on a secondary display. -->
- <style name="Theme.DeviceDefault.Light.Dialog.Presentation" parent="Theme.Material.Light.Dialog.Presentation" />
+ <style name="Theme.DeviceDefault.Light.Dialog.Presentation" parent="Theme.Material.Light.Dialog.Presentation">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_light</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
+ </style>
<!-- DeviceDefault light 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.DeviceDefault.Light.Panel" parent="Theme.Material.Light.Panel" />
+ <style name="Theme.DeviceDefault.Light.Panel" parent="Theme.Material.Light.Panel">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_light</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
+ </style>
<style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.Alert">
<item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault.Light</item>
+
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_light</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
</style>
- <style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.Material.Light.SearchBar" />
+ <style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.Material.Light.SearchBar">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_light</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
+ </style>
+
<!-- DeviceDefault theme for a window that should look like the Settings app. -->
- <style name="Theme.DeviceDefault.Settings" parent="Theme.Material.Settings" />
+ <style name="Theme.DeviceDefault.Settings" parent="Theme.Material.Settings">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_settings</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
+ <item name="colorSecondary">@color/secondary_device_default_settings</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
+ </style>
+
+ <!-- DeviceDefault theme for a window that should use Settings theme colors but has
+ a full dark palette (instead of Light with dark action bar like
+ Theme.DeviceDefault.Settings. -->
+ <style name="Theme.DeviceDefault.Settings.Dark" parent="Theme.Material">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_settings</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
+ <item name="colorSecondary">@color/secondary_device_default_settings</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ </style>
+
+ <style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.Material.Settings.Dialog">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_settings</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
+ <item name="colorSecondary">@color/secondary_device_default_settings</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
+ </style>
+
+ <style name="Theme.DeviceDefault.Settings.DialogWhenLarge" parent="Theme.Material.Settings.DialogWhenLarge">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_settings</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
+ <item name="colorSecondary">@color/secondary_device_default_settings</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
+ </style>
+
+ <style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.Alert">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_settings</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
+ <item name="colorSecondary">@color/secondary_device_default_settings</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
+ </style>
<!-- Theme used for the intent picker activity. -->
<style name="Theme.DeviceDefault.Resolver" parent="Theme.Material.Light">
@@ -549,8 +780,28 @@
<item name="colorControlActivated">?attr/colorControlHighlight</item>
<item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item>
<item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item>
+
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_device_default_light</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
</style>
<!-- DeviceDefault theme for the default system theme. -->
- <style name="Theme.DeviceDefault.System" parent="Theme.Material.Light.DarkActionBar" />
+ <style name="Theme.DeviceDefault.System" parent="Theme.DeviceDefault.Light.DarkActionBar" />
+
+ <style name="ThemeOverlay.DeviceDefault" />
+
+ <style name="ThemeOverlay.DeviceDefault.Accent">
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ </style>
+
+ <style name="ThemeOverlay.DeviceDefault.Accent.Light">
+ <item name="colorAccent">@color/accent_device_default_light</item>
+ </style>
+
+ <style name="ThemeOverlay.DeviceDefault.Dark.ActionBar.Accent" parent="ThemeOverlay.Material.Dark.ActionBar">
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ </style>
+
</resources>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 0e4e060..35ce9b0 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -864,17 +864,14 @@
<item name="searchViewStyle">@style/Widget.Material.SearchView.ActionBar</item>
</style>
- <!-- Theme overlay that overrides window properties to display as a dialog. -->
- <style name="ThemeOverlay.Material.Dialog">
- <item name="colorBackgroundCacheHint">@null</item>
- <item name="colorBackground">?attr/colorBackgroundFloating</item>
-
+ <!-- Base theme for overlay dialogs, customize the colours in the actual dialog theme. -->
+ <style name="ThemeOverlay.Material.BaseDialog">
<item name="windowFrame">@null</item>
<item name="windowTitleStyle">@style/DialogWindowTitle.Material</item>
<item name="windowTitleBackgroundStyle">@style/DialogWindowTitleBackground.Material</item>
<item name="windowBackground">@drawable/dialog_background_material</item>
<item name="windowElevation">@dimen/floating_window_z</item>
- <item name="windowIsFloating">@bool/config_dialogWindowIsFloating</item>
+ <item name="windowIsFloating">true</item>
<item name="windowContentOverlay">@null</item>
<item name="windowAnimationStyle">@style/Animation.Material.Dialog</item>
<item name="windowSoftInputMode">stateUnspecified|adjustPan</item>
@@ -897,6 +894,12 @@
<item name="windowFixedHeightMinor">@null</item>
</style>
+ <!-- Theme overlay that overrides window properties to display as a dialog. -->
+ <style name="ThemeOverlay.Material.Dialog" parent="ThemeOverlay.Material.BaseDialog">
+ <item name="colorBackgroundCacheHint">@null</item>
+ <item name="colorBackground">?attr/colorBackgroundFloating</item>
+ </style>
+
<!-- Theme overlay that overrides window properties to display as a date picker dialog. -->
<style name="ThemeOverlay.Material.Dialog.DatePicker">
<item name="alertDialogStyle">@style/DatePickerDialog.Material</item>
@@ -1080,7 +1083,7 @@
<item name="windowTitleBackgroundStyle">@style/DialogWindowTitleBackground.Material</item>
<item name="windowBackground">@drawable/dialog_background_material</item>
<item name="windowElevation">@dimen/floating_window_z</item>
- <item name="windowIsFloating">@bool/config_dialogWindowIsFloating</item>
+ <item name="windowIsFloating">true</item>
<item name="windowContentOverlay">@null</item>
<item name="windowAnimationStyle">@style/Animation.Material.Dialog</item>
<item name="windowSoftInputMode">stateUnspecified|adjustPan</item>
@@ -1300,8 +1303,9 @@
<!-- Default theme for Settings and activities launched from Settings. -->
<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>
+ <item name="colorPrimary">@color/primary_material_settings</item>
+ <item name="colorPrimaryDark">@color/primary_dark_material_settings</item>
+ <item name="colorSecondary">@color/secondary_material_settings</item>
<item name="presentationTheme">@style/Theme.Material.Settings.Dialog.Presentation</item>
<item name="searchDialogTheme">@style/Theme.Material.Settings.SearchBar</item>
@@ -1310,8 +1314,9 @@
<!-- Default theme for Settings and activities launched from Settings. -->
<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>
+ <item name="colorPrimary">@color/primary_material_settings</item>
+ <item name="colorPrimaryDark">@color/primary_dark_material_settings</item>
+ <item name="colorSecondary">@color/secondary_material_settings</item>
<item name="presentationTheme">@style/Theme.Material.Settings.Dialog.Presentation</item>
<item name="searchDialogTheme">@style/Theme.Material.Settings.SearchBar</item>
@@ -1319,41 +1324,48 @@
</style>
<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>
+ <item name="colorPrimary">@color/primary_material_settings</item>
+ <item name="colorPrimaryDark">@color/primary_dark_material_settings</item>
+ <item name="colorSecondary">@color/secondary_material_settings</item>
</style>
<style name="Theme.Material.Settings.Dialog" parent="Theme.Material.Settings.BaseDialog" />
<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>
+ <item name="colorPrimary">@color/primary_material_settings</item>
+ <item name="colorPrimaryDark">@color/primary_dark_material_settings</item>
+ <item name="colorSecondary">@color/secondary_material_settings</item>
</style>
<style name="Theme.Material.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.BaseAlert" />
<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>
+ <item name="colorPrimary">@color/primary_material_settings</item>
+ <item name="colorPrimaryDark">@color/primary_dark_material_settings</item>
+ <item name="colorSecondary">@color/secondary_material_settings</item>
</style>
<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>
+ <item name="colorPrimary">@color/primary_material_settings</item>
+ <item name="colorPrimaryDark">@color/primary_dark_material_settings</item>
+ <item name="colorSecondary">@color/secondary_material_settings</item>
</style>
<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>
+ <item name="colorPrimary">@color/primary_material_settings</item>
+ <item name="colorPrimaryDark">@color/primary_dark_material_settings</item>
+ <item name="colorSecondary">@color/secondary_material_settings</item>
</style>
<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>
+ <item name="colorPrimary">@color/primary_material_settings</item>
+ <item name="colorPrimaryDark">@color/primary_dark_material_settings</item>
+ <item name="colorSecondary">@color/secondary_material_settings</item>
</style>
<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>
+ <item name="colorPrimary">@color/primary_material_settings</item>
+ <item name="colorPrimaryDark">@color/primary_dark_material_settings</item>
+ <item name="colorSecondary">@color/secondary_material_settings</item>
</style>
</resources>
diff --git a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
index 39a2907..f088197 100644
--- a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
+++ b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
@@ -23,6 +23,8 @@
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Display;
+import android.view.DisplayAdjustments;
+
import junit.framework.TestCase;
public class ResourcesManagerTest extends TestCase {
@@ -58,7 +60,7 @@
}
@Override
- protected DisplayMetrics getDisplayMetrics(int displayId) {
+ protected DisplayMetrics getDisplayMetrics(int displayId, DisplayAdjustments daj) {
return mDisplayMetrics;
}
};
diff --git a/core/tests/notificationtests/src/android/app/NotificationStressTest.java b/core/tests/notificationtests/src/android/app/NotificationStressTest.java
index 6e86c37..f174014 100644
--- a/core/tests/notificationtests/src/android/app/NotificationStressTest.java
+++ b/core/tests/notificationtests/src/android/app/NotificationStressTest.java
@@ -40,9 +40,9 @@
private static final int NUM_ITERATIONS = 200;
private static final int NUM_ITERATIONS_2 = 30;
private static final int LONG_TIMEOUT = 2000;
- // 50 notifications per app: defined as Variable MAX_PACKAGE_NOTIFICATIONS in
+ // 49 notifications per app: defined as Variable MAX_PACKAGE_NOTIFICATIONS in
// NotificationManagerService.java
- private static final int MAX_NOTIFCATIONS = 50;
+ private static final int MAX_NOTIFCATIONS = 49;
private static final int[] ICONS = new int[] {
android.R.drawable.stat_notify_call_mute,
android.R.drawable.stat_notify_chat,
@@ -76,9 +76,10 @@
@Override
protected void tearDown() throws Exception {
- super.tearDown();
mDevice.unfreezeRotation();
mNotificationManager.cancelAll();
+ mDevice.waitForIdle();
+ super.tearDown();
}
@RepetitiveTest(numIterations = NUM_ITERATIONS)
@@ -97,7 +98,7 @@
for (int j = 0; j < MAX_NOTIFCATIONS; j++) {
sendNotification(mNotifyId++, "testNotificationStressNotify");
}
- Thread.sleep(500);
+ Thread.sleep(LONG_TIMEOUT);
assertTrue(mNotificationManager.getActiveNotifications().length == MAX_NOTIFCATIONS);
for (int j = 0; j < MAX_NOTIFCATIONS; j++) {
mNotificationManager.cancel(--mNotifyId);
@@ -124,7 +125,8 @@
.setPriority(Notification.PRIORITY_HIGH)
.build();
mNotificationManager.notify(id, notification);
- SystemClock.sleep(10);
+ //update rate limit is 50 notifications/second.
+ SystemClock.sleep(20);
}
private boolean isLockScreen() {
diff --git a/docs/html-intl/intl/es/preview/images/bundles.png b/docs/html-intl/intl/es/preview/images/bundles.png
deleted file mode 100644
index 8b022b1..0000000
--- a/docs/html-intl/intl/es/preview/images/bundles.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/bundles_2x.png b/docs/html-intl/intl/es/preview/images/bundles_2x.png
deleted file mode 100644
index 4669096..0000000
--- a/docs/html-intl/intl/es/preview/images/bundles_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/datasaver.png b/docs/html-intl/intl/es/preview/images/datasaver.png
deleted file mode 100644
index c5a58fb..0000000
--- a/docs/html-intl/intl/es/preview/images/datasaver.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/doze-diagram-1.png b/docs/html-intl/intl/es/preview/images/doze-diagram-1.png
deleted file mode 100644
index 0814447..0000000
--- a/docs/html-intl/intl/es/preview/images/doze-diagram-1.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/doze-diagram-2.png b/docs/html-intl/intl/es/preview/images/doze-diagram-2.png
deleted file mode 100644
index c20c6cb..0000000
--- a/docs/html-intl/intl/es/preview/images/doze-diagram-2.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/inline-reply.png b/docs/html-intl/intl/es/preview/images/inline-reply.png
deleted file mode 100644
index 79a1a72..0000000
--- a/docs/html-intl/intl/es/preview/images/inline-reply.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/inline-reply_2x.png b/docs/html-intl/intl/es/preview/images/inline-reply_2x.png
deleted file mode 100644
index 13c6e35..0000000
--- a/docs/html-intl/intl/es/preview/images/inline-reply_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/inline-type-reply.png b/docs/html-intl/intl/es/preview/images/inline-type-reply.png
deleted file mode 100644
index b22aacd..0000000
--- a/docs/html-intl/intl/es/preview/images/inline-type-reply.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/inline-type-reply_2x.png b/docs/html-intl/intl/es/preview/images/inline-type-reply_2x.png
deleted file mode 100644
index 6e52a80..0000000
--- a/docs/html-intl/intl/es/preview/images/inline-type-reply_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/m-preview-timeline-crop.png b/docs/html-intl/intl/es/preview/images/m-preview-timeline-crop.png
deleted file mode 100644
index 724a6af..0000000
--- a/docs/html-intl/intl/es/preview/images/m-preview-timeline-crop.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/m-preview-timeline.png b/docs/html-intl/intl/es/preview/images/m-preview-timeline.png
deleted file mode 100644
index e9a339e..0000000
--- a/docs/html-intl/intl/es/preview/images/m-preview-timeline.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/mw-portrait.png b/docs/html-intl/intl/es/preview/images/mw-portrait.png
deleted file mode 100644
index e752387..0000000
--- a/docs/html-intl/intl/es/preview/images/mw-portrait.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/mw-splitscreen.png b/docs/html-intl/intl/es/preview/images/mw-splitscreen.png
deleted file mode 100644
index bf71999..0000000
--- a/docs/html-intl/intl/es/preview/images/mw-splitscreen.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/mw-splitscreen_2x.png b/docs/html-intl/intl/es/preview/images/mw-splitscreen_2x.png
deleted file mode 100644
index 38114db..0000000
--- a/docs/html-intl/intl/es/preview/images/mw-splitscreen_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/n-preview-setup.png b/docs/html-intl/intl/es/preview/images/n-preview-setup.png
deleted file mode 100644
index 612e031..0000000
--- a/docs/html-intl/intl/es/preview/images/n-preview-setup.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/notifications-1.png b/docs/html-intl/intl/es/preview/images/notifications-1.png
deleted file mode 100644
index 5712002..0000000
--- a/docs/html-intl/intl/es/preview/images/notifications-1.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/notifications-2.png b/docs/html-intl/intl/es/preview/images/notifications-2.png
deleted file mode 100644
index 0d07948..0000000
--- a/docs/html-intl/intl/es/preview/images/notifications-2.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/notifications-3.png b/docs/html-intl/intl/es/preview/images/notifications-3.png
deleted file mode 100644
index 261d010..0000000
--- a/docs/html-intl/intl/es/preview/images/notifications-3.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/notifications-card.png b/docs/html-intl/intl/es/preview/images/notifications-card.png
deleted file mode 100644
index d9d0590..0000000
--- a/docs/html-intl/intl/es/preview/images/notifications-card.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/pip-active.png b/docs/html-intl/intl/es/preview/images/pip-active.png
deleted file mode 100644
index a24cb03..0000000
--- a/docs/html-intl/intl/es/preview/images/pip-active.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/pip-button.png b/docs/html-intl/intl/es/preview/images/pip-button.png
deleted file mode 100644
index b876b12..0000000
--- a/docs/html-intl/intl/es/preview/images/pip-button.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/quicksettings.png b/docs/html-intl/intl/es/preview/images/quicksettings.png
deleted file mode 100644
index 68e1f74..0000000
--- a/docs/html-intl/intl/es/preview/images/quicksettings.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/sample-activenotifications.png b/docs/html-intl/intl/es/preview/images/sample-activenotifications.png
deleted file mode 100644
index 8817469..0000000
--- a/docs/html-intl/intl/es/preview/images/sample-activenotifications.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/sample-directboot.png b/docs/html-intl/intl/es/preview/images/sample-directboot.png
deleted file mode 100644
index cc409d3..0000000
--- a/docs/html-intl/intl/es/preview/images/sample-directboot.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/sample-messagingservice.png b/docs/html-intl/intl/es/preview/images/sample-messagingservice.png
deleted file mode 100644
index 0d8fb3e..0000000
--- a/docs/html-intl/intl/es/preview/images/sample-messagingservice.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/sample-multiwindow.png b/docs/html-intl/intl/es/preview/images/sample-multiwindow.png
deleted file mode 100644
index 979bf61..0000000
--- a/docs/html-intl/intl/es/preview/images/sample-multiwindow.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/sample-scopeddirectoryaccess.png b/docs/html-intl/intl/es/preview/images/sample-scopeddirectoryaccess.png
deleted file mode 100644
index 58515dc..0000000
--- a/docs/html-intl/intl/es/preview/images/sample-scopeddirectoryaccess.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/scoped-folder-access-dont-ask.png b/docs/html-intl/intl/es/preview/images/scoped-folder-access-dont-ask.png
deleted file mode 100644
index 5c505d9..0000000
--- a/docs/html-intl/intl/es/preview/images/scoped-folder-access-dont-ask.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/scoped-folder-access-dont-ask_2x.png b/docs/html-intl/intl/es/preview/images/scoped-folder-access-dont-ask_2x.png
deleted file mode 100644
index 612b69f..0000000
--- a/docs/html-intl/intl/es/preview/images/scoped-folder-access-dont-ask_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/scoped-folder-access-framed.png b/docs/html-intl/intl/es/preview/images/scoped-folder-access-framed.png
deleted file mode 100644
index 0169e41..0000000
--- a/docs/html-intl/intl/es/preview/images/scoped-folder-access-framed.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/scoped-folder-access-framed_2x.png b/docs/html-intl/intl/es/preview/images/scoped-folder-access-framed_2x.png
deleted file mode 100644
index fd59ef1..0000000
--- a/docs/html-intl/intl/es/preview/images/scoped-folder-access-framed_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/screen-zoom-1.png b/docs/html-intl/intl/es/preview/images/screen-zoom-1.png
deleted file mode 100644
index f62d04e..0000000
--- a/docs/html-intl/intl/es/preview/images/screen-zoom-1.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/screen-zoom-2.png b/docs/html-intl/intl/es/preview/images/screen-zoom-2.png
deleted file mode 100644
index 172b5b3..0000000
--- a/docs/html-intl/intl/es/preview/images/screen-zoom-2.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/es/preview/images/studio-jdk-location.jpg b/docs/html-intl/intl/es/preview/images/studio-jdk-location.jpg
deleted file mode 100644
index 1b1ba23..0000000
--- a/docs/html-intl/intl/es/preview/images/studio-jdk-location.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/bundles.png b/docs/html-intl/intl/in/preview/images/bundles.png
deleted file mode 100644
index 8b022b1..0000000
--- a/docs/html-intl/intl/in/preview/images/bundles.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/bundles_2x.png b/docs/html-intl/intl/in/preview/images/bundles_2x.png
deleted file mode 100644
index 4669096..0000000
--- a/docs/html-intl/intl/in/preview/images/bundles_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/datasaver.png b/docs/html-intl/intl/in/preview/images/datasaver.png
deleted file mode 100644
index c5a58fb..0000000
--- a/docs/html-intl/intl/in/preview/images/datasaver.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/doze-diagram-1.png b/docs/html-intl/intl/in/preview/images/doze-diagram-1.png
deleted file mode 100644
index 0814447..0000000
--- a/docs/html-intl/intl/in/preview/images/doze-diagram-1.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/doze-diagram-2.png b/docs/html-intl/intl/in/preview/images/doze-diagram-2.png
deleted file mode 100644
index c20c6cb..0000000
--- a/docs/html-intl/intl/in/preview/images/doze-diagram-2.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/inline-reply.png b/docs/html-intl/intl/in/preview/images/inline-reply.png
deleted file mode 100644
index 79a1a72..0000000
--- a/docs/html-intl/intl/in/preview/images/inline-reply.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/inline-reply_2x.png b/docs/html-intl/intl/in/preview/images/inline-reply_2x.png
deleted file mode 100644
index 13c6e35..0000000
--- a/docs/html-intl/intl/in/preview/images/inline-reply_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/inline-type-reply.png b/docs/html-intl/intl/in/preview/images/inline-type-reply.png
deleted file mode 100644
index b22aacd..0000000
--- a/docs/html-intl/intl/in/preview/images/inline-type-reply.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/inline-type-reply_2x.png b/docs/html-intl/intl/in/preview/images/inline-type-reply_2x.png
deleted file mode 100644
index 6e52a80..0000000
--- a/docs/html-intl/intl/in/preview/images/inline-type-reply_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/m-preview-timeline-crop.png b/docs/html-intl/intl/in/preview/images/m-preview-timeline-crop.png
deleted file mode 100644
index 724a6af..0000000
--- a/docs/html-intl/intl/in/preview/images/m-preview-timeline-crop.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/m-preview-timeline.png b/docs/html-intl/intl/in/preview/images/m-preview-timeline.png
deleted file mode 100644
index e9a339e..0000000
--- a/docs/html-intl/intl/in/preview/images/m-preview-timeline.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/mw-portrait.png b/docs/html-intl/intl/in/preview/images/mw-portrait.png
deleted file mode 100644
index e752387..0000000
--- a/docs/html-intl/intl/in/preview/images/mw-portrait.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/mw-splitscreen.png b/docs/html-intl/intl/in/preview/images/mw-splitscreen.png
deleted file mode 100644
index bf71999..0000000
--- a/docs/html-intl/intl/in/preview/images/mw-splitscreen.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/mw-splitscreen_2x.png b/docs/html-intl/intl/in/preview/images/mw-splitscreen_2x.png
deleted file mode 100644
index 38114db..0000000
--- a/docs/html-intl/intl/in/preview/images/mw-splitscreen_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/n-preview-setup.png b/docs/html-intl/intl/in/preview/images/n-preview-setup.png
deleted file mode 100644
index 612e031..0000000
--- a/docs/html-intl/intl/in/preview/images/n-preview-setup.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/notifications-1.png b/docs/html-intl/intl/in/preview/images/notifications-1.png
deleted file mode 100644
index 5712002..0000000
--- a/docs/html-intl/intl/in/preview/images/notifications-1.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/notifications-2.png b/docs/html-intl/intl/in/preview/images/notifications-2.png
deleted file mode 100644
index 0d07948..0000000
--- a/docs/html-intl/intl/in/preview/images/notifications-2.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/notifications-3.png b/docs/html-intl/intl/in/preview/images/notifications-3.png
deleted file mode 100644
index 261d010..0000000
--- a/docs/html-intl/intl/in/preview/images/notifications-3.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/notifications-card.png b/docs/html-intl/intl/in/preview/images/notifications-card.png
deleted file mode 100644
index d9d0590..0000000
--- a/docs/html-intl/intl/in/preview/images/notifications-card.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/pip-active.png b/docs/html-intl/intl/in/preview/images/pip-active.png
deleted file mode 100644
index a24cb03..0000000
--- a/docs/html-intl/intl/in/preview/images/pip-active.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/pip-button.png b/docs/html-intl/intl/in/preview/images/pip-button.png
deleted file mode 100644
index b876b12..0000000
--- a/docs/html-intl/intl/in/preview/images/pip-button.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/quicksettings.png b/docs/html-intl/intl/in/preview/images/quicksettings.png
deleted file mode 100644
index 68e1f74..0000000
--- a/docs/html-intl/intl/in/preview/images/quicksettings.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/sample-activenotifications.png b/docs/html-intl/intl/in/preview/images/sample-activenotifications.png
deleted file mode 100644
index 8817469..0000000
--- a/docs/html-intl/intl/in/preview/images/sample-activenotifications.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/sample-directboot.png b/docs/html-intl/intl/in/preview/images/sample-directboot.png
deleted file mode 100644
index cc409d3..0000000
--- a/docs/html-intl/intl/in/preview/images/sample-directboot.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/sample-messagingservice.png b/docs/html-intl/intl/in/preview/images/sample-messagingservice.png
deleted file mode 100644
index 0d8fb3e..0000000
--- a/docs/html-intl/intl/in/preview/images/sample-messagingservice.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/sample-multiwindow.png b/docs/html-intl/intl/in/preview/images/sample-multiwindow.png
deleted file mode 100644
index 979bf61..0000000
--- a/docs/html-intl/intl/in/preview/images/sample-multiwindow.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/sample-scopeddirectoryaccess.png b/docs/html-intl/intl/in/preview/images/sample-scopeddirectoryaccess.png
deleted file mode 100644
index 58515dc..0000000
--- a/docs/html-intl/intl/in/preview/images/sample-scopeddirectoryaccess.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/scoped-folder-access-dont-ask.png b/docs/html-intl/intl/in/preview/images/scoped-folder-access-dont-ask.png
deleted file mode 100644
index 5c505d9..0000000
--- a/docs/html-intl/intl/in/preview/images/scoped-folder-access-dont-ask.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/scoped-folder-access-dont-ask_2x.png b/docs/html-intl/intl/in/preview/images/scoped-folder-access-dont-ask_2x.png
deleted file mode 100644
index 612b69f..0000000
--- a/docs/html-intl/intl/in/preview/images/scoped-folder-access-dont-ask_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/scoped-folder-access-framed.png b/docs/html-intl/intl/in/preview/images/scoped-folder-access-framed.png
deleted file mode 100644
index 0169e41..0000000
--- a/docs/html-intl/intl/in/preview/images/scoped-folder-access-framed.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/scoped-folder-access-framed_2x.png b/docs/html-intl/intl/in/preview/images/scoped-folder-access-framed_2x.png
deleted file mode 100644
index fd59ef1..0000000
--- a/docs/html-intl/intl/in/preview/images/scoped-folder-access-framed_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/screen-zoom-1.png b/docs/html-intl/intl/in/preview/images/screen-zoom-1.png
deleted file mode 100644
index f62d04e..0000000
--- a/docs/html-intl/intl/in/preview/images/screen-zoom-1.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/screen-zoom-2.png b/docs/html-intl/intl/in/preview/images/screen-zoom-2.png
deleted file mode 100644
index 172b5b3..0000000
--- a/docs/html-intl/intl/in/preview/images/screen-zoom-2.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/in/preview/images/studio-jdk-location.jpg b/docs/html-intl/intl/in/preview/images/studio-jdk-location.jpg
deleted file mode 100644
index 1b1ba23..0000000
--- a/docs/html-intl/intl/in/preview/images/studio-jdk-location.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/bundles.png b/docs/html-intl/intl/ja/preview/images/bundles.png
deleted file mode 100644
index 8b022b1..0000000
--- a/docs/html-intl/intl/ja/preview/images/bundles.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/bundles_2x.png b/docs/html-intl/intl/ja/preview/images/bundles_2x.png
deleted file mode 100644
index 4669096..0000000
--- a/docs/html-intl/intl/ja/preview/images/bundles_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/datasaver.png b/docs/html-intl/intl/ja/preview/images/datasaver.png
deleted file mode 100644
index c5a58fb..0000000
--- a/docs/html-intl/intl/ja/preview/images/datasaver.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/doze-diagram-1.png b/docs/html-intl/intl/ja/preview/images/doze-diagram-1.png
deleted file mode 100644
index 0814447..0000000
--- a/docs/html-intl/intl/ja/preview/images/doze-diagram-1.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/doze-diagram-2.png b/docs/html-intl/intl/ja/preview/images/doze-diagram-2.png
deleted file mode 100644
index c20c6cb..0000000
--- a/docs/html-intl/intl/ja/preview/images/doze-diagram-2.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/inline-reply.png b/docs/html-intl/intl/ja/preview/images/inline-reply.png
deleted file mode 100644
index 79a1a72..0000000
--- a/docs/html-intl/intl/ja/preview/images/inline-reply.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/inline-reply_2x.png b/docs/html-intl/intl/ja/preview/images/inline-reply_2x.png
deleted file mode 100644
index 13c6e35..0000000
--- a/docs/html-intl/intl/ja/preview/images/inline-reply_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/inline-type-reply.png b/docs/html-intl/intl/ja/preview/images/inline-type-reply.png
deleted file mode 100644
index b22aacd..0000000
--- a/docs/html-intl/intl/ja/preview/images/inline-type-reply.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/inline-type-reply_2x.png b/docs/html-intl/intl/ja/preview/images/inline-type-reply_2x.png
deleted file mode 100644
index 6e52a80..0000000
--- a/docs/html-intl/intl/ja/preview/images/inline-type-reply_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/m-preview-timeline-crop.png b/docs/html-intl/intl/ja/preview/images/m-preview-timeline-crop.png
deleted file mode 100644
index 724a6af..0000000
--- a/docs/html-intl/intl/ja/preview/images/m-preview-timeline-crop.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/m-preview-timeline.png b/docs/html-intl/intl/ja/preview/images/m-preview-timeline.png
deleted file mode 100644
index e9a339e..0000000
--- a/docs/html-intl/intl/ja/preview/images/m-preview-timeline.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/mw-portrait.png b/docs/html-intl/intl/ja/preview/images/mw-portrait.png
deleted file mode 100644
index e752387..0000000
--- a/docs/html-intl/intl/ja/preview/images/mw-portrait.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/mw-splitscreen.png b/docs/html-intl/intl/ja/preview/images/mw-splitscreen.png
deleted file mode 100644
index bf71999..0000000
--- a/docs/html-intl/intl/ja/preview/images/mw-splitscreen.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/mw-splitscreen_2x.png b/docs/html-intl/intl/ja/preview/images/mw-splitscreen_2x.png
deleted file mode 100644
index 38114db..0000000
--- a/docs/html-intl/intl/ja/preview/images/mw-splitscreen_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/n-preview-setup.png b/docs/html-intl/intl/ja/preview/images/n-preview-setup.png
deleted file mode 100644
index 612e031..0000000
--- a/docs/html-intl/intl/ja/preview/images/n-preview-setup.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/notifications-1.png b/docs/html-intl/intl/ja/preview/images/notifications-1.png
deleted file mode 100644
index 5712002..0000000
--- a/docs/html-intl/intl/ja/preview/images/notifications-1.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/notifications-2.png b/docs/html-intl/intl/ja/preview/images/notifications-2.png
deleted file mode 100644
index 0d07948..0000000
--- a/docs/html-intl/intl/ja/preview/images/notifications-2.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/notifications-3.png b/docs/html-intl/intl/ja/preview/images/notifications-3.png
deleted file mode 100644
index 261d010..0000000
--- a/docs/html-intl/intl/ja/preview/images/notifications-3.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/notifications-card.png b/docs/html-intl/intl/ja/preview/images/notifications-card.png
deleted file mode 100644
index d9d0590..0000000
--- a/docs/html-intl/intl/ja/preview/images/notifications-card.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/pip-active.png b/docs/html-intl/intl/ja/preview/images/pip-active.png
deleted file mode 100644
index a24cb03..0000000
--- a/docs/html-intl/intl/ja/preview/images/pip-active.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/pip-button.png b/docs/html-intl/intl/ja/preview/images/pip-button.png
deleted file mode 100644
index b876b12..0000000
--- a/docs/html-intl/intl/ja/preview/images/pip-button.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/quicksettings.png b/docs/html-intl/intl/ja/preview/images/quicksettings.png
deleted file mode 100644
index 68e1f74..0000000
--- a/docs/html-intl/intl/ja/preview/images/quicksettings.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/sample-activenotifications.png b/docs/html-intl/intl/ja/preview/images/sample-activenotifications.png
deleted file mode 100644
index 8817469..0000000
--- a/docs/html-intl/intl/ja/preview/images/sample-activenotifications.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/sample-directboot.png b/docs/html-intl/intl/ja/preview/images/sample-directboot.png
deleted file mode 100644
index cc409d3..0000000
--- a/docs/html-intl/intl/ja/preview/images/sample-directboot.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/sample-messagingservice.png b/docs/html-intl/intl/ja/preview/images/sample-messagingservice.png
deleted file mode 100644
index 0d8fb3e..0000000
--- a/docs/html-intl/intl/ja/preview/images/sample-messagingservice.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/sample-multiwindow.png b/docs/html-intl/intl/ja/preview/images/sample-multiwindow.png
deleted file mode 100644
index 979bf61..0000000
--- a/docs/html-intl/intl/ja/preview/images/sample-multiwindow.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/sample-scopeddirectoryaccess.png b/docs/html-intl/intl/ja/preview/images/sample-scopeddirectoryaccess.png
deleted file mode 100644
index 58515dc..0000000
--- a/docs/html-intl/intl/ja/preview/images/sample-scopeddirectoryaccess.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/scoped-folder-access-dont-ask.png b/docs/html-intl/intl/ja/preview/images/scoped-folder-access-dont-ask.png
deleted file mode 100644
index 5c505d9..0000000
--- a/docs/html-intl/intl/ja/preview/images/scoped-folder-access-dont-ask.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/scoped-folder-access-dont-ask_2x.png b/docs/html-intl/intl/ja/preview/images/scoped-folder-access-dont-ask_2x.png
deleted file mode 100644
index 612b69f..0000000
--- a/docs/html-intl/intl/ja/preview/images/scoped-folder-access-dont-ask_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/scoped-folder-access-framed.png b/docs/html-intl/intl/ja/preview/images/scoped-folder-access-framed.png
deleted file mode 100644
index 0169e41..0000000
--- a/docs/html-intl/intl/ja/preview/images/scoped-folder-access-framed.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/scoped-folder-access-framed_2x.png b/docs/html-intl/intl/ja/preview/images/scoped-folder-access-framed_2x.png
deleted file mode 100644
index fd59ef1..0000000
--- a/docs/html-intl/intl/ja/preview/images/scoped-folder-access-framed_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/screen-zoom-1.png b/docs/html-intl/intl/ja/preview/images/screen-zoom-1.png
deleted file mode 100644
index f62d04e..0000000
--- a/docs/html-intl/intl/ja/preview/images/screen-zoom-1.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/screen-zoom-2.png b/docs/html-intl/intl/ja/preview/images/screen-zoom-2.png
deleted file mode 100644
index 172b5b3..0000000
--- a/docs/html-intl/intl/ja/preview/images/screen-zoom-2.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ja/preview/images/studio-jdk-location.jpg b/docs/html-intl/intl/ja/preview/images/studio-jdk-location.jpg
deleted file mode 100644
index 1b1ba23..0000000
--- a/docs/html-intl/intl/ja/preview/images/studio-jdk-location.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/bundles.png b/docs/html-intl/intl/ko/preview/images/bundles.png
deleted file mode 100644
index 8b022b1..0000000
--- a/docs/html-intl/intl/ko/preview/images/bundles.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/bundles_2x.png b/docs/html-intl/intl/ko/preview/images/bundles_2x.png
deleted file mode 100644
index 4669096..0000000
--- a/docs/html-intl/intl/ko/preview/images/bundles_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/datasaver.png b/docs/html-intl/intl/ko/preview/images/datasaver.png
deleted file mode 100644
index c5a58fb..0000000
--- a/docs/html-intl/intl/ko/preview/images/datasaver.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/doze-diagram-1.png b/docs/html-intl/intl/ko/preview/images/doze-diagram-1.png
deleted file mode 100644
index 0814447..0000000
--- a/docs/html-intl/intl/ko/preview/images/doze-diagram-1.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/doze-diagram-2.png b/docs/html-intl/intl/ko/preview/images/doze-diagram-2.png
deleted file mode 100644
index c20c6cb..0000000
--- a/docs/html-intl/intl/ko/preview/images/doze-diagram-2.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/inline-reply.png b/docs/html-intl/intl/ko/preview/images/inline-reply.png
deleted file mode 100644
index 79a1a72..0000000
--- a/docs/html-intl/intl/ko/preview/images/inline-reply.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/inline-reply_2x.png b/docs/html-intl/intl/ko/preview/images/inline-reply_2x.png
deleted file mode 100644
index 13c6e35..0000000
--- a/docs/html-intl/intl/ko/preview/images/inline-reply_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/inline-type-reply.png b/docs/html-intl/intl/ko/preview/images/inline-type-reply.png
deleted file mode 100644
index b22aacd..0000000
--- a/docs/html-intl/intl/ko/preview/images/inline-type-reply.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/inline-type-reply_2x.png b/docs/html-intl/intl/ko/preview/images/inline-type-reply_2x.png
deleted file mode 100644
index 6e52a80..0000000
--- a/docs/html-intl/intl/ko/preview/images/inline-type-reply_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/m-preview-timeline-crop.png b/docs/html-intl/intl/ko/preview/images/m-preview-timeline-crop.png
deleted file mode 100644
index 724a6af..0000000
--- a/docs/html-intl/intl/ko/preview/images/m-preview-timeline-crop.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/m-preview-timeline.png b/docs/html-intl/intl/ko/preview/images/m-preview-timeline.png
deleted file mode 100644
index e9a339e..0000000
--- a/docs/html-intl/intl/ko/preview/images/m-preview-timeline.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/mw-portrait.png b/docs/html-intl/intl/ko/preview/images/mw-portrait.png
deleted file mode 100644
index e752387..0000000
--- a/docs/html-intl/intl/ko/preview/images/mw-portrait.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/mw-splitscreen.png b/docs/html-intl/intl/ko/preview/images/mw-splitscreen.png
deleted file mode 100644
index bf71999..0000000
--- a/docs/html-intl/intl/ko/preview/images/mw-splitscreen.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/mw-splitscreen_2x.png b/docs/html-intl/intl/ko/preview/images/mw-splitscreen_2x.png
deleted file mode 100644
index 38114db..0000000
--- a/docs/html-intl/intl/ko/preview/images/mw-splitscreen_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/n-preview-setup.png b/docs/html-intl/intl/ko/preview/images/n-preview-setup.png
deleted file mode 100644
index 612e031..0000000
--- a/docs/html-intl/intl/ko/preview/images/n-preview-setup.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/notifications-1.png b/docs/html-intl/intl/ko/preview/images/notifications-1.png
deleted file mode 100644
index 5712002..0000000
--- a/docs/html-intl/intl/ko/preview/images/notifications-1.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/notifications-2.png b/docs/html-intl/intl/ko/preview/images/notifications-2.png
deleted file mode 100644
index 0d07948..0000000
--- a/docs/html-intl/intl/ko/preview/images/notifications-2.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/notifications-3.png b/docs/html-intl/intl/ko/preview/images/notifications-3.png
deleted file mode 100644
index 261d010..0000000
--- a/docs/html-intl/intl/ko/preview/images/notifications-3.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/notifications-card.png b/docs/html-intl/intl/ko/preview/images/notifications-card.png
deleted file mode 100644
index d9d0590..0000000
--- a/docs/html-intl/intl/ko/preview/images/notifications-card.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/pip-active.png b/docs/html-intl/intl/ko/preview/images/pip-active.png
deleted file mode 100644
index a24cb03..0000000
--- a/docs/html-intl/intl/ko/preview/images/pip-active.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/pip-button.png b/docs/html-intl/intl/ko/preview/images/pip-button.png
deleted file mode 100644
index b876b12..0000000
--- a/docs/html-intl/intl/ko/preview/images/pip-button.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/quicksettings.png b/docs/html-intl/intl/ko/preview/images/quicksettings.png
deleted file mode 100644
index 68e1f74..0000000
--- a/docs/html-intl/intl/ko/preview/images/quicksettings.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/sample-activenotifications.png b/docs/html-intl/intl/ko/preview/images/sample-activenotifications.png
deleted file mode 100644
index 8817469..0000000
--- a/docs/html-intl/intl/ko/preview/images/sample-activenotifications.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/sample-directboot.png b/docs/html-intl/intl/ko/preview/images/sample-directboot.png
deleted file mode 100644
index cc409d3..0000000
--- a/docs/html-intl/intl/ko/preview/images/sample-directboot.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/sample-messagingservice.png b/docs/html-intl/intl/ko/preview/images/sample-messagingservice.png
deleted file mode 100644
index 0d8fb3e..0000000
--- a/docs/html-intl/intl/ko/preview/images/sample-messagingservice.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/sample-multiwindow.png b/docs/html-intl/intl/ko/preview/images/sample-multiwindow.png
deleted file mode 100644
index 979bf61..0000000
--- a/docs/html-intl/intl/ko/preview/images/sample-multiwindow.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/sample-scopeddirectoryaccess.png b/docs/html-intl/intl/ko/preview/images/sample-scopeddirectoryaccess.png
deleted file mode 100644
index 58515dc..0000000
--- a/docs/html-intl/intl/ko/preview/images/sample-scopeddirectoryaccess.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/scoped-folder-access-dont-ask.png b/docs/html-intl/intl/ko/preview/images/scoped-folder-access-dont-ask.png
deleted file mode 100644
index 5c505d9..0000000
--- a/docs/html-intl/intl/ko/preview/images/scoped-folder-access-dont-ask.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/scoped-folder-access-dont-ask_2x.png b/docs/html-intl/intl/ko/preview/images/scoped-folder-access-dont-ask_2x.png
deleted file mode 100644
index 612b69f..0000000
--- a/docs/html-intl/intl/ko/preview/images/scoped-folder-access-dont-ask_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/scoped-folder-access-framed.png b/docs/html-intl/intl/ko/preview/images/scoped-folder-access-framed.png
deleted file mode 100644
index 0169e41..0000000
--- a/docs/html-intl/intl/ko/preview/images/scoped-folder-access-framed.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/scoped-folder-access-framed_2x.png b/docs/html-intl/intl/ko/preview/images/scoped-folder-access-framed_2x.png
deleted file mode 100644
index fd59ef1..0000000
--- a/docs/html-intl/intl/ko/preview/images/scoped-folder-access-framed_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/screen-zoom-1.png b/docs/html-intl/intl/ko/preview/images/screen-zoom-1.png
deleted file mode 100644
index f62d04e..0000000
--- a/docs/html-intl/intl/ko/preview/images/screen-zoom-1.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/screen-zoom-2.png b/docs/html-intl/intl/ko/preview/images/screen-zoom-2.png
deleted file mode 100644
index 172b5b3..0000000
--- a/docs/html-intl/intl/ko/preview/images/screen-zoom-2.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/ko/preview/images/studio-jdk-location.jpg b/docs/html-intl/intl/ko/preview/images/studio-jdk-location.jpg
deleted file mode 100644
index 1b1ba23..0000000
--- a/docs/html-intl/intl/ko/preview/images/studio-jdk-location.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/bundles.png b/docs/html-intl/intl/pt-br/preview/images/bundles.png
deleted file mode 100644
index 8b022b1..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/bundles.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/bundles_2x.png b/docs/html-intl/intl/pt-br/preview/images/bundles_2x.png
deleted file mode 100644
index 4669096..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/bundles_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/datasaver.png b/docs/html-intl/intl/pt-br/preview/images/datasaver.png
deleted file mode 100644
index c5a58fb..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/datasaver.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/doze-diagram-1.png b/docs/html-intl/intl/pt-br/preview/images/doze-diagram-1.png
deleted file mode 100644
index 0814447..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/doze-diagram-1.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/doze-diagram-2.png b/docs/html-intl/intl/pt-br/preview/images/doze-diagram-2.png
deleted file mode 100644
index c20c6cb..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/doze-diagram-2.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/inline-reply.png b/docs/html-intl/intl/pt-br/preview/images/inline-reply.png
deleted file mode 100644
index 79a1a72..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/inline-reply.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/inline-reply_2x.png b/docs/html-intl/intl/pt-br/preview/images/inline-reply_2x.png
deleted file mode 100644
index 13c6e35..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/inline-reply_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/inline-type-reply.png b/docs/html-intl/intl/pt-br/preview/images/inline-type-reply.png
deleted file mode 100644
index b22aacd..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/inline-type-reply.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/inline-type-reply_2x.png b/docs/html-intl/intl/pt-br/preview/images/inline-type-reply_2x.png
deleted file mode 100644
index 6e52a80..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/inline-type-reply_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/m-preview-timeline-crop.png b/docs/html-intl/intl/pt-br/preview/images/m-preview-timeline-crop.png
deleted file mode 100644
index 724a6af..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/m-preview-timeline-crop.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/m-preview-timeline.png b/docs/html-intl/intl/pt-br/preview/images/m-preview-timeline.png
deleted file mode 100644
index e9a339e..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/m-preview-timeline.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/mw-portrait.png b/docs/html-intl/intl/pt-br/preview/images/mw-portrait.png
deleted file mode 100644
index e752387..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/mw-portrait.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/mw-splitscreen.png b/docs/html-intl/intl/pt-br/preview/images/mw-splitscreen.png
deleted file mode 100644
index bf71999..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/mw-splitscreen.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/mw-splitscreen_2x.png b/docs/html-intl/intl/pt-br/preview/images/mw-splitscreen_2x.png
deleted file mode 100644
index 38114db..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/mw-splitscreen_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/n-preview-setup.png b/docs/html-intl/intl/pt-br/preview/images/n-preview-setup.png
deleted file mode 100644
index 612e031..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/n-preview-setup.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/notifications-1.png b/docs/html-intl/intl/pt-br/preview/images/notifications-1.png
deleted file mode 100644
index 5712002..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/notifications-1.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/notifications-2.png b/docs/html-intl/intl/pt-br/preview/images/notifications-2.png
deleted file mode 100644
index 0d07948..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/notifications-2.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/notifications-3.png b/docs/html-intl/intl/pt-br/preview/images/notifications-3.png
deleted file mode 100644
index 261d010..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/notifications-3.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/notifications-card.png b/docs/html-intl/intl/pt-br/preview/images/notifications-card.png
deleted file mode 100644
index d9d0590..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/notifications-card.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/pip-active.png b/docs/html-intl/intl/pt-br/preview/images/pip-active.png
deleted file mode 100644
index a24cb03..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/pip-active.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/pip-button.png b/docs/html-intl/intl/pt-br/preview/images/pip-button.png
deleted file mode 100644
index b876b12..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/pip-button.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/quicksettings.png b/docs/html-intl/intl/pt-br/preview/images/quicksettings.png
deleted file mode 100644
index 68e1f74..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/quicksettings.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/sample-activenotifications.png b/docs/html-intl/intl/pt-br/preview/images/sample-activenotifications.png
deleted file mode 100644
index 8817469..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/sample-activenotifications.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/sample-directboot.png b/docs/html-intl/intl/pt-br/preview/images/sample-directboot.png
deleted file mode 100644
index cc409d3..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/sample-directboot.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/sample-messagingservice.png b/docs/html-intl/intl/pt-br/preview/images/sample-messagingservice.png
deleted file mode 100644
index 0d8fb3e..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/sample-messagingservice.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/sample-multiwindow.png b/docs/html-intl/intl/pt-br/preview/images/sample-multiwindow.png
deleted file mode 100644
index 979bf61..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/sample-multiwindow.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/sample-scopeddirectoryaccess.png b/docs/html-intl/intl/pt-br/preview/images/sample-scopeddirectoryaccess.png
deleted file mode 100644
index 58515dc..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/sample-scopeddirectoryaccess.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/scoped-folder-access-dont-ask.png b/docs/html-intl/intl/pt-br/preview/images/scoped-folder-access-dont-ask.png
deleted file mode 100644
index 5c505d9..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/scoped-folder-access-dont-ask.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/scoped-folder-access-dont-ask_2x.png b/docs/html-intl/intl/pt-br/preview/images/scoped-folder-access-dont-ask_2x.png
deleted file mode 100644
index 612b69f..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/scoped-folder-access-dont-ask_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/scoped-folder-access-framed.png b/docs/html-intl/intl/pt-br/preview/images/scoped-folder-access-framed.png
deleted file mode 100644
index 0169e41..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/scoped-folder-access-framed.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/scoped-folder-access-framed_2x.png b/docs/html-intl/intl/pt-br/preview/images/scoped-folder-access-framed_2x.png
deleted file mode 100644
index fd59ef1..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/scoped-folder-access-framed_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/screen-zoom-1.png b/docs/html-intl/intl/pt-br/preview/images/screen-zoom-1.png
deleted file mode 100644
index f62d04e..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/screen-zoom-1.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/screen-zoom-2.png b/docs/html-intl/intl/pt-br/preview/images/screen-zoom-2.png
deleted file mode 100644
index 172b5b3..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/screen-zoom-2.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/pt-br/preview/images/studio-jdk-location.jpg b/docs/html-intl/intl/pt-br/preview/images/studio-jdk-location.jpg
deleted file mode 100644
index 1b1ba23..0000000
--- a/docs/html-intl/intl/pt-br/preview/images/studio-jdk-location.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/bundles.png b/docs/html-intl/intl/zh-cn/preview/images/bundles.png
deleted file mode 100644
index 8b022b1..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/bundles.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/bundles_2x.png b/docs/html-intl/intl/zh-cn/preview/images/bundles_2x.png
deleted file mode 100644
index 4669096..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/bundles_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/datasaver.png b/docs/html-intl/intl/zh-cn/preview/images/datasaver.png
deleted file mode 100644
index c5a58fb..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/datasaver.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/doze-diagram-1.png b/docs/html-intl/intl/zh-cn/preview/images/doze-diagram-1.png
deleted file mode 100644
index 0814447..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/doze-diagram-1.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/doze-diagram-2.png b/docs/html-intl/intl/zh-cn/preview/images/doze-diagram-2.png
deleted file mode 100644
index c20c6cb..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/doze-diagram-2.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/inline-reply.png b/docs/html-intl/intl/zh-cn/preview/images/inline-reply.png
deleted file mode 100644
index 79a1a72..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/inline-reply.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/inline-reply_2x.png b/docs/html-intl/intl/zh-cn/preview/images/inline-reply_2x.png
deleted file mode 100644
index 13c6e35..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/inline-reply_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/inline-type-reply.png b/docs/html-intl/intl/zh-cn/preview/images/inline-type-reply.png
deleted file mode 100644
index b22aacd..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/inline-type-reply.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/inline-type-reply_2x.png b/docs/html-intl/intl/zh-cn/preview/images/inline-type-reply_2x.png
deleted file mode 100644
index 6e52a80..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/inline-type-reply_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/m-preview-timeline-crop.png b/docs/html-intl/intl/zh-cn/preview/images/m-preview-timeline-crop.png
deleted file mode 100644
index 724a6af..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/m-preview-timeline-crop.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/m-preview-timeline.png b/docs/html-intl/intl/zh-cn/preview/images/m-preview-timeline.png
deleted file mode 100644
index e9a339e..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/m-preview-timeline.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/mw-portrait.png b/docs/html-intl/intl/zh-cn/preview/images/mw-portrait.png
deleted file mode 100644
index e752387..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/mw-portrait.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/mw-splitscreen.png b/docs/html-intl/intl/zh-cn/preview/images/mw-splitscreen.png
deleted file mode 100644
index bf71999..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/mw-splitscreen.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/mw-splitscreen_2x.png b/docs/html-intl/intl/zh-cn/preview/images/mw-splitscreen_2x.png
deleted file mode 100644
index 38114db..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/mw-splitscreen_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/n-preview-setup.png b/docs/html-intl/intl/zh-cn/preview/images/n-preview-setup.png
deleted file mode 100644
index 612e031..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/n-preview-setup.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/notifications-1.png b/docs/html-intl/intl/zh-cn/preview/images/notifications-1.png
deleted file mode 100644
index 5712002..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/notifications-1.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/notifications-2.png b/docs/html-intl/intl/zh-cn/preview/images/notifications-2.png
deleted file mode 100644
index 0d07948..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/notifications-2.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/notifications-3.png b/docs/html-intl/intl/zh-cn/preview/images/notifications-3.png
deleted file mode 100644
index 261d010..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/notifications-3.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/notifications-card.png b/docs/html-intl/intl/zh-cn/preview/images/notifications-card.png
deleted file mode 100644
index d9d0590..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/notifications-card.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/pip-active.png b/docs/html-intl/intl/zh-cn/preview/images/pip-active.png
deleted file mode 100644
index a24cb03..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/pip-active.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/pip-button.png b/docs/html-intl/intl/zh-cn/preview/images/pip-button.png
deleted file mode 100644
index b876b12..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/pip-button.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/quicksettings.png b/docs/html-intl/intl/zh-cn/preview/images/quicksettings.png
deleted file mode 100644
index 68e1f74..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/quicksettings.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/sample-activenotifications.png b/docs/html-intl/intl/zh-cn/preview/images/sample-activenotifications.png
deleted file mode 100644
index 8817469..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/sample-activenotifications.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/sample-directboot.png b/docs/html-intl/intl/zh-cn/preview/images/sample-directboot.png
deleted file mode 100644
index cc409d3..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/sample-directboot.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/sample-messagingservice.png b/docs/html-intl/intl/zh-cn/preview/images/sample-messagingservice.png
deleted file mode 100644
index 0d8fb3e..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/sample-messagingservice.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/sample-multiwindow.png b/docs/html-intl/intl/zh-cn/preview/images/sample-multiwindow.png
deleted file mode 100644
index 979bf61..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/sample-multiwindow.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/sample-scopeddirectoryaccess.png b/docs/html-intl/intl/zh-cn/preview/images/sample-scopeddirectoryaccess.png
deleted file mode 100644
index 58515dc..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/sample-scopeddirectoryaccess.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/scoped-folder-access-dont-ask.png b/docs/html-intl/intl/zh-cn/preview/images/scoped-folder-access-dont-ask.png
deleted file mode 100644
index 5c505d9..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/scoped-folder-access-dont-ask.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/scoped-folder-access-dont-ask_2x.png b/docs/html-intl/intl/zh-cn/preview/images/scoped-folder-access-dont-ask_2x.png
deleted file mode 100644
index 612b69f..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/scoped-folder-access-dont-ask_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/scoped-folder-access-framed.png b/docs/html-intl/intl/zh-cn/preview/images/scoped-folder-access-framed.png
deleted file mode 100644
index 0169e41..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/scoped-folder-access-framed.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/scoped-folder-access-framed_2x.png b/docs/html-intl/intl/zh-cn/preview/images/scoped-folder-access-framed_2x.png
deleted file mode 100644
index fd59ef1..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/scoped-folder-access-framed_2x.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/screen-zoom-1.png b/docs/html-intl/intl/zh-cn/preview/images/screen-zoom-1.png
deleted file mode 100644
index f62d04e..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/screen-zoom-1.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/screen-zoom-2.png b/docs/html-intl/intl/zh-cn/preview/images/screen-zoom-2.png
deleted file mode 100644
index 172b5b3..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/screen-zoom-2.png
+++ /dev/null
Binary files differ
diff --git a/docs/html-intl/intl/zh-cn/preview/images/studio-jdk-location.jpg b/docs/html-intl/intl/zh-cn/preview/images/studio-jdk-location.jpg
deleted file mode 100644
index 1b1ba23..0000000
--- a/docs/html-intl/intl/zh-cn/preview/images/studio-jdk-location.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/_redirects.yaml b/docs/html/_redirects.yaml
index ae858fe..6e1cc23 100644
--- a/docs/html/_redirects.yaml
+++ b/docs/html/_redirects.yaml
@@ -797,54 +797,6 @@
to: https://code.google.com/p/android/issues/list?can=2&q=label%3ADevPreview-N
- from: /2016/03/first-preview-of-android-n-developer.html
to: http://android-developers.blogspot.com/2016/03/first-preview-of-android-n-developer.html
-- from: /r/studio-ui/vector-asset-studio.html
- to: /studio/write/vector-asset-studio.html
-- from: /r/studio-ui/image-asset-studio.html
- to: /studio/write/image-asset-studio.html
-- from: /r/studio-ui/project-structure.html
- to: /studio/projects/index.html
-- from: /r/studio-ui/android-monitor.html
- to: /studio/profile/android-monitor.html
-- from: /r/studio-ui/am-logcat.html
- to: /studio/debug/am-logcat.html
-- from: /r/studio-ui/am-memory.html
- to: /studio/profile/am-memory.html
-- from: /r/studio-ui/am-cpu.html
- to: /studio/profile/am-cpu.html
-- from: /r/studio-ui/am-gpu.html
- to: /studio/profile/am-gpu.html
-- from: /r/studio-ui/am-network.html
- to: /studio/profile/am-network.html
-- from: /r/studio-ui/am-hprof.html
- to: /studio/profile/am-hprof.html
-- from: /r/studio-ui/am-allocation.html
- to: /studio/profile/am-allocation.html
-- from: /r/studio-ui/am-methodtrace.html
- to: /studio/profile/am-methodtrace.html
-- from: /r/studio-ui/am-sysinfo.html
- to: /studio/profile/am-sysinfo.html
-- from: /r/studio-ui/am-screenshot.html
- to: /studio/debug/am-screenshot.html
-- from: /r/studio-ui/am-video.html
- to: /studio/debug/am-video.html
-- from: /r/studio-ui/avd-manager.html
- to: /studio/run/managing-avds.html
-- from: /r/studio-ui/rundebugconfig.html
- to: /studio/run/index.html
-- from: /r/studio-ui/devicechooser.html
- to: /studio/run/emulator.html
-- from: /r/studio-ui/virtualdeviceconfig.html
- to: /studio/run/managing-avds.html
-- from: /r/studio-ui/emulator.html
- to: /studio/run/emulator.html
-- from: /r/studio-ui/instant-run.html
- to: /studio/run/index.html#instant-run
-- from: /r/studio-ui/test-recorder.html
- to: http://tools.android.com/tech-docs/test-recorder
-- from: /r/studio-ui/export-licenses.html
- to: http://tools.android.com/tech-docs/new-build-system/license
-- from: /r/studio-ui/experimental-to-stable-gradle.html
- to: http://tools.android.com/tech-docs/new-build-system/gradle-experimental/experimental-to-stable-gradle
- from: /reference/org/apache/http/...
to: /about/versions/marshmallow/android-6.0-changes.html#behavior-apache-http-client
- from: /shareables/...
@@ -1066,6 +1018,8 @@
to: /studio/projects/templates.html
- from: /tools/publishing/app-signing.html
to: /studio/publish/app-signing.html
+- from: /guide/publishing/app-signing.html
+ to: /studio/publish/app-signing.html
- from: /tools/publishing/preparing.html
to: /studio/publish/preparing.html
- from: /tools/publishing/publishing_overview.html
@@ -1169,3 +1123,57 @@
to: /preview/features/background-optimization.html
- from: /bgopt/
to: /preview/features/background-optimization.html
+
+
+
+# Android Studio help button redirects
+- from: /r/studio-ui/vector-asset-studio.html
+ to: /studio/write/vector-asset-studio.html
+- from: /r/studio-ui/image-asset-studio.html
+ to: /studio/write/image-asset-studio.html
+- from: /r/studio-ui/project-structure.html
+ to: /studio/projects/index.html
+- from: /r/studio-ui/android-monitor.html
+ to: /studio/profile/android-monitor.html
+- from: /r/studio-ui/am-logcat.html
+ to: /studio/debug/am-logcat.html
+- from: /r/studio-ui/am-memory.html
+ to: /studio/profile/am-memory.html
+- from: /r/studio-ui/am-cpu.html
+ to: /studio/profile/am-cpu.html
+- from: /r/studio-ui/am-gpu.html
+ to: /studio/profile/am-gpu.html
+- from: /r/studio-ui/am-network.html
+ to: /studio/profile/am-network.html
+- from: /r/studio-ui/am-hprof.html
+ to: /studio/profile/am-hprof.html
+- from: /r/studio-ui/am-allocation.html
+ to: /studio/profile/am-allocation.html
+- from: /r/studio-ui/am-methodtrace.html
+ to: /studio/profile/am-methodtrace.html
+- from: /r/studio-ui/am-sysinfo.html
+ to: /studio/profile/am-sysinfo.html
+- from: /r/studio-ui/am-screenshot.html
+ to: /studio/debug/am-screenshot.html
+- from: /r/studio-ui/am-video.html
+ to: /studio/debug/am-video.html
+- from: /r/studio-ui/avd-manager.html
+ to: /studio/run/managing-avds.html
+- from: /r/studio-ui/rundebugconfig.html
+ to: /studio/run/index.html
+- from: /r/studio-ui/devicechooser.html
+ to: /studio/run/emulator.html
+- from: /r/studio-ui/virtualdeviceconfig.html
+ to: /studio/run/managing-avds.html
+- from: /r/studio-ui/emulator.html
+ to: /studio/run/emulator.html
+- from: /r/studio-ui/instant-run.html
+ to: /studio/run/index.html#instant-run
+- from: /r/studio-ui/test-recorder.html
+ to: http://tools.android.com/tech-docs/test-recorder
+- from: /r/studio-ui/export-licenses.html
+ to: http://tools.android.com/tech-docs/new-build-system/license
+- from: /r/studio-ui/experimental-to-stable-gradle.html
+ to: http://tools.android.com/tech-docs/new-build-system/gradle-experimental/experimental-to-stable-gradle
+- from: /r/studio-ui/sdk-manager.html
+ to: https://developer.android.com/studio/intro/update.html#sdk-manager
\ No newline at end of file
diff --git a/docs/html/distribute/essentials/quality/core.jd b/docs/html/distribute/essentials/quality/core.jd
index 4b0b546..0ff44eb 100644
--- a/docs/html/distribute/essentials/quality/core.jd
+++ b/docs/html/distribute/essentials/quality/core.jd
@@ -1041,7 +1041,7 @@
CR-11
</td>
<td>
- Trigger and observe in the notications drawer all types of notifications
+ Trigger and observe in the notifications drawer all types of notifications
that the app can display. Expand notifications where applicable (Android
4.1 and higher), and tap all actions offered.
</td>
diff --git a/docs/html/google/play/billing/billing_admin.jd b/docs/html/google/play/billing/billing_admin.jd
index a1135bf..05f3ad5 100644
--- a/docs/html/google/play/billing/billing_admin.jd
+++ b/docs/html/google/play/billing/billing_admin.jd
@@ -747,6 +747,15 @@
<code>orderId</code> field of the <code>PURCHASE_STATE_CHANGED</code>
intent.</p>
+<p class="note">
+ <strong>Note:</strong> When a user completes a test purchase, the
+ <code>orderId</code> field remains blank. To track test transactions, use
+ the <code>purchaseToken</code> field instead. For more information about
+ working with test purchases, see <a
+ href="{@docRoot}google/play/billing/billing_testing.html">Testing In-app
+ Billing</a>.
+</p>
+
<p>In your app, you can use the order number as a general-purpose identifier for
the in-app purchase transaction. After the purchase, you can use the order
number as a means of tracking the transaction in reconciliation reports and for
diff --git a/docs/html/google/play/billing/billing_testing.jd b/docs/html/google/play/billing/billing_testing.jd
index 018276d..755f3ff 100644
--- a/docs/html/google/play/billing/billing_testing.jd
+++ b/docs/html/google/play/billing/billing_testing.jd
@@ -79,14 +79,11 @@
through Google Play without incurring any actual charges to the user
accounts.</p>
-<p>Once authorized for testing access, those users can make purchases without
-being charged.
-Test purchases are real orders and Google Play processes them in the same way as
-other orders. However, the <code>orderId</code> field for test purchases is
-blank.
-When purchases are complete, Google Play prevents the orders from
-going to financial processing, ensuring that there are no actual charges to user
-accounts, and automatically canceling the completed orders after 14 days.</p>
+<p>
+ Once authorized for testing access, those users can make purchases without
+ being charged. The <code>orderId</code> field for test purchases remains
+ blank, ensuring that there are no actual charges to user accounts.
+</p>
<p class="note">
<strong>Note:</strong> Test subscription purchases recur daily, regardless of
@@ -130,8 +127,8 @@
purchase dialog.</p>
<p class="note">
- <strong>Note:</strong> For test subscription purchases, leave the {@code orderId}
- field blank. You can use the {@code purchaseToken} field to identify test purchases.
+ <strong>Note:</strong> For test purchases, leave the {@code orderId} field
+ blank. You can use the {@code purchaseToken} field to identify test purchases.
</p>
@@ -150,33 +147,22 @@
<h4 id="cancelling">Canceling completed test purchases</h4>
<p>Google Play accumulates completed test purchases for each user but does not
-pass them on to financial processing. Over time, it automatically clears out
-the purchases by canceling them. </p>
+pass them on to financial processing.</p>
<p>In some cases, you might want to manually cancel a test purchase to continue
-testing. For canceling purchases, you have these options:</p>
-
-<ul>
-<li>Wait for the transactions to expire—Google Play clears completed test
-purchases 14 days after their purchase date. </li>
-<li>Cancel purchases manually—you can go to the Google payments merchant
-center, look up the transaction, and then cancel it. You can find transactions
-by looking up their order numbers.</li>
+testing. To do so, open the app page in the Play Store. If the test purchase
+that you want to cancel is a subscription, you can also use the
+<a href="https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/cancel">
+{@code cancel()}</a> method of the Purchases.subscriptions API.
</ul>
-<p>
- You can cancel test subscriptions purchases from the app page in the Play Store,
- or use the
- <a href="https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/cancel">
- {@code cancel}</a> method.
-</p>
-
<p class="caution">
<strong>Important:</strong> The
<a href="https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/refund">
- {@code refund}</a> and
+ {@code refund()}</a> and
<a href="https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/revoke">
- {@code revoke}</a> methods do not support test purchases.
+ {@code revoke()}</a> methods of the Purchases.subscriptions API don't support
+ test purchases.
</p>
diff --git a/docs/html/guide/topics/renderscript/compute.jd b/docs/html/guide/topics/renderscript/compute.jd
index 564215e..fc795ff 100755
--- a/docs/html/guide/topics/renderscript/compute.jd
+++ b/docs/html/guide/topics/renderscript/compute.jd
@@ -21,7 +21,7 @@
<h2>Related Samples</h2>
<ol>
- <li><a href="{@docRoot}resources/samples/RenderScript/HelloCompute/index.html">Hello
+ <li><a class="external-link"href="https://github.com/android/platform_development/tree/master/samples/RenderScript/HelloCompute">Hello
Compute</a></li>
</ol>
</div>
diff --git a/docs/html/images/testing/test-types.zip b/docs/html/images/testing/test-types.zip
new file mode 100644
index 0000000..d433b91
--- /dev/null
+++ b/docs/html/images/testing/test-types.zip
Binary files differ
diff --git a/docs/html/images/testing/test-types_2x.png b/docs/html/images/testing/test-types_2x.png
new file mode 100644
index 0000000..0a374aa
--- /dev/null
+++ b/docs/html/images/testing/test-types_2x.png
Binary files differ
diff --git a/docs/html/ndk/downloads/index.jd b/docs/html/ndk/downloads/index.jd
index 47d3113..954b049 100644
--- a/docs/html/ndk/downloads/index.jd
+++ b/docs/html/ndk/downloads/index.jd
@@ -332,35 +332,199 @@
<h2 id="rel">Release Notes</h2>
<p>
- Android NDK, Revision 11c <em>(March 2016)</em>
+ Android NDK, Revision 12 <em>(June 2016)</em>
</p>
<dl>
- <dt>
- NDK
- </dt>
+<dt>
+ Announcements
+</dt>
- <dd>
- <ul>
- <li>Changes
- <ul>
- <li>Applied additional fixes to the {@code ndk-gdb.py} script.
- </li>
- <li>Added an optional package name argument to the {@code ndk-gdb}
- command {@code --attach} option.
- (<a href="https://github.com/android-ndk/ndk/issues/13">Issue 13</a>)
- </li>
- <li>Fixed invalid toolchain paths for 32-bit Windows platform.
- (<a href="https://github.com/android-ndk/ndk/issues/45">Issue 45</a>)
- </li>
- <li>Fixed the relative path for the {@code ndk-which} command.
- (<a href="https://github.com/android-ndk/ndk/issues/29">Issue 29</a>)
- </li>
- <li>Fixed use of cygpath for the libgcc compiler.
- (Android <a href="http://b.android.com/195486">Issue 195486</a>)
- </li>
- </ul>
- </li>
- </ul>
- </dd>
-</dl>
\ No newline at end of file
+<ul>
+ <li>The <code>ndk-build</code> command will default to using
+ Clang in an upcoming release. GCC will be removed in a later release.
+ </li>
+ <li>The <code>make-standalone-toolchain.sh</code> script will be removed
+ in an upcoming release. If you use this script, please plan to migrate to the
+ <code>make_standalone_toolchain.py</code> as soon as possible.
+ </li>
+</ul>
+
+<dt>
+ NDK
+</dt>
+
+<ul>
+ <li>Removed support for the armeabi-v7a-hard ABI. See the explanation in the
+ <a href=
+ "https://android.googlesource.com/platform/ndk/+/ndk-r12-release/docs/HardFloatAbi.md">
+ documentation</a>.
+ </li>
+
+ <li>Removed all sysroots for platform levels prior to Android 2.3 (API level 10).
+ We dropped support for them in NDK r11, but neglected to actually remove them.
+ </li>
+
+ <li>Updated exception handling when using c++_shared on ARM32 so that it
+ mostly works (see <a href="#known-issues">Known Issues</a>). The unwinder
+ is now linked into each linked object rather than into libc++ itself.
+ </li>
+
+ <li>Pruned the default compiler flags (<a href=
+ "https://github.com/android-ndk/ndk/issues/27">NDK Issue 27</a>). You can see
+ details of this update in <a href=
+ "https://android-review.googlesource.com/#/c/207721/5">Change 207721</a>.
+ </li>
+
+ <li>Added a Python implementation of standalone toolchains in <code>
+ build/tools/make_standalone_toolchain.py</code>. On Windows, you no longer
+ need Cygwin to use this feature. Note that the bash flavor will be removed
+ in an upcoming release, so please test the new one now.
+ </li>
+
+ <li>Configured Clang debug builds to have the <code>-fno-limit-debug-info</code>
+ option is enabled by default. This change enables better debugging with LLDB.
+ </li>
+
+ <li>Enabled the <code>--build-id</code> as a default option. This option
+ causes an identifier to be shown in native crash reports so you can easily
+ identify which version of your code was running.
+ </li>
+
+ <li>Fixed issue with <code>NDK_USE_CYGPATH</code> so that it no longer causes
+ problems with libgcc
+ (<a href="http://b.android.com/195486">Issue 195486</a>).
+ </li>
+
+ <li>Enabled the following options as default:
+ <code>-Wl,--warn-shared-textrel</code> and <code>-Wl,--fatal-warnings</code>.
+ If you have shared text relocations, your app does not load on Android 6.0
+ (API level 23) and higher. Note that this configuration has never been
+ allowed for 64-bit apps.
+ </li>
+
+ <li>Fixed a few issues so that precompiled headers work better
+ (<a href="https://github.com/android-ndk/ndk/issues/14">NDK Issue 14</a>,
+ <a href="https://github.com/android-ndk/ndk/issues/16">NDK Issue 16</a>).
+ </li>
+
+ <li>Removed unreachable ARM (non-thumb) STL libraries.
+ </li>
+
+ <li>Added Vulkan support to android-24.
+ </li>
+
+ <li>Added Choreographer API to android-24.
+ </li>
+
+ <li>Added libcamera2 APIs for devices that support the
+ <code>INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED</code> feature level or higher.
+ For more information, see the
+ <a href="{@docRoot}reference/android/hardware/camera2/CameraCharacteristics.html#INFO_SUPPORTED_HARDWARE_LEVEL">
+ <code>CameraCharacteristics</code></a> reference.
+ </li>
+
+</ul>
+
+<dt>
+ Clang
+</dt>
+
+<ul>
+ <li>Clang has been updated to 3.8svn (r256229, build 2812033). Note that
+ Clang packaged in the Windows 64-bit NDK is actually 32-bit.
+ </li>
+
+ <li>Fixed <code>__thread</code> so that it works for real this time.
+ </li>
+</ul>
+
+<dt>
+ GCC
+</dt>
+
+<ul>
+ <li>Synchronized the compiler with the ChromeOS GCC @ google/gcc-4_9 r227810.
+ </li>
+
+ <li>Backported coverage sanitizer patch from ToT (r231296).
+ </li>
+
+ <li>Fixed <code>libatomic</code> to not use ifuncs (<a href=
+ "https://github.com/android-ndk/ndk/issues/31">NDK Issue 31</a>).
+ </li>
+</ul>
+
+<dt>
+ Binutils
+</dt>
+
+<ul>
+ <li>Silenced the "Erratum 843419 found and fixed" info messages.
+ </li>
+
+ <li>Introduced option <code>--long-plt</code> to fix an internal linker error
+ when linking huge arm32 binaries.
+ </li>
+
+ <li>Fixed wrong run time stubs for <code>AArch64</code>. This problem was
+ causing jump addresses to be calculated incorrectly for very large
+ dynamic shared objects (DSOs).
+ </li>
+
+ <li>Introduced default option <code>--no-apply-dynamic</code> to work around
+ a dynamic linker bug for earlier Android releases.
+ </li>
+
+ <li>Fixed a known issue with NDK r11 where <code>dynamic_cast</code> was not
+ working with Clang, x86, stlport_static and optimization.
+ </li>
+</ul>
+
+<dt>
+ GDB
+</dt>
+
+<ul>
+ <li>Updated to GDB version 7.11. For more information about this release, see
+ <a href="https://www.gnu.org/software/gdb/news/">GDB News</a>.
+ </li>
+
+ <li>Fixed a number of bugs in the <code>ndk-gdb.py</code> script.
+ </li>
+</ul>
+
+<dt id="known-issues">
+ Known Issues
+</dt>
+
+<ul>
+ <li>The x86 <a href="http://source.android.com/devices/tech/debug/asan.html">Address
+ Sanitizer</a> (ASAN) currently does not work. For more information, see
+ <a href="https://android-review.googlesource.com/#/c/186276/">Issue 186276</a>.
+ </li>
+
+ <li>Exception unwinding with <code>c++_shared</code> does not work for ARM on
+ Android 2.3 (API level 9) or Android 4.0 (API level 14).
+ </li>
+
+ <li>Bionic headers and libraries for Android 6.0 (API level 23) and higher
+ are not yet exposed despite the presence of android-24. Those platforms still
+ have the Android 5.0 (API level 21) headers and libraries, which is consistent
+ with NDK r11.
+ </li>
+
+ <li>The RenderScript tools are not present, which is consistent with
+ NDK r11.
+ (<a href="https://github.com/android-ndk/ndk/issues/7">NDK Issue 7</a>)
+ </li>
+
+ <li>In <code>NdkCameraMetadataTags.h</code> header file, the camera metadata
+ tag enum value <code>ACAMERA_STATISTICS_LENS_SHADING_CORRECTION_MAP</code>
+ was listed by accident and will be removed in next release. Use
+ the <code>ACAMERA_STATISTICS_LENS_SHADING_MAP</code> value instead.
+ </li>
+
+</ul>
+
+</dl>
diff --git a/docs/html/ndk/downloads/revision_history.jd b/docs/html/ndk/downloads/revision_history.jd
index c5a0d48..211b64e 100644
--- a/docs/html/ndk/downloads/revision_history.jd
+++ b/docs/html/ndk/downloads/revision_history.jd
@@ -10,6 +10,44 @@
<p>
<a href="#" onclick="return toggleContent(this)"> <img
src="/assets/images/styles/disclosure_down.png" class="toggle-content-img" alt=""
+ >Android NDK, Revision 11c</a> <em>(March 2016)</em>
+ </p>
+ <div class="toggle-content-toggleme">
+
+<dl>
+ <dd>
+ <ul>
+ <li>Changes
+ <ul>
+ <li>Applied additional fixes to the {@code ndk-gdb.py} script.
+ </li>
+ <li>Added an optional package name argument to the {@code ndk-gdb}
+ command {@code --attach} option.
+ (<a href="https://github.com/android-ndk/ndk/issues/13">Issue 13</a>)
+ </li>
+ <li>Fixed invalid toolchain paths for 32-bit Windows platform.
+ (<a href="https://github.com/android-ndk/ndk/issues/45">Issue 45</a>)
+ </li>
+ <li>Fixed the relative path for the {@code ndk-which} command.
+ (<a href="https://github.com/android-ndk/ndk/issues/29">Issue 29</a>)
+ </li>
+ <li>Fixed use of cygpath for the libgcc compiler.
+ (Android <a href="http://b.android.com/195486">Issue 195486</a>)
+ </li>
+ </ul>
+ </li>
+ </ul>
+ </dd>
+</dl>
+
+ </div>
+</div>
+
+<div class="toggle-content closed">
+<a name="11b"></a>
+ <p>
+ <a href="#" onclick="return toggleContent(this)"> <img
+ src="/assets/images/styles/disclosure_down.png" class="toggle-content-img" alt=""
>Android NDK, Revision 11b</a> <em>(March 2016)</em>
</p>
<div class="toggle-content-toggleme">
diff --git a/docs/html/preview/support.jd b/docs/html/preview/support.jd
index 5328fd8..ef8a652 100644
--- a/docs/html/preview/support.jd
+++ b/docs/html/preview/support.jd
@@ -17,6 +17,7 @@
<li><a href="#general">General advisories</a></li>
<li><a href="#new">New in DP4</a></li>
<li><a href="#ki">Known issues</a></li>
+ <li><a href="#upgrade-notes">Notes on publishing apps that target API 24</a></li>
</ul>
</li>
<li><a href="#dp3">Developer Preview 3</a></li>
@@ -279,6 +280,15 @@
</li>
</ul>
+<h4 id="">Android Auto</h4>
+
+<p>
+ The version of Google Maps included in Developer Preview 4 (9.30) crashes
+ when used with Android Auto. This issue will be fixed in the next update to
+ Google Maps (9.31), expected in the coming weeks.
+</p>
+
+
<!-- TBA, if any
<h4>Device-specific issues</h4>
@@ -328,13 +338,34 @@
<li>Additional bluetooth connectivity fixes
</li>
+
</ul>
<p>For the full list of fixed issues, see <a href="https://goo.gl/6uCKtf">the
issue tracker</a>.</p>
+<h3 id="upgrade-notes">Notes on publishing apps that target API 24</h3>
+<p>
+ Before publishing apps that target API 24 in Google Play, keep these points
+ in mind:
+</p>
+<ul>
+ <li>If your app’s current <code>targetSdkVersion</code> is 22 or lower and
+ you want to target API 24, you’ll need to support <a href=
+ "{@docRoot}about/versions/marshmallow/android-6.0-changes.html">behaviors
+ introduced with Android 6.0 (Marshmallow)</a>, such as <a href=
+ "{@docRoot}training/permissions/requesting.html">runtime permissions</a>, in
+ addition to Android N behaviors.
+ </li>
+
+ <li>Once you publish an app with <code>targetSdkVersion</code> set to 23 or
+ higher, you can't later publish a version of the app with a higher
+ <code>versionCode</code> that targets 22 or lower. This restriction applies
+ in alpha and beta channels as well as production channel.
+ </li>
+</ul>
<!-- DP3 Release Notes Archive -->
diff --git a/docs/html/sdk/sdk_vars.cs b/docs/html/sdk/sdk_vars.cs
index 32fdb0a..80da297 100644
--- a/docs/html/sdk/sdk_vars.cs
+++ b/docs/html/sdk/sdk_vars.cs
@@ -1,18 +1,19 @@
<?cs
-set:ndk.mac64_download='android-ndk-r11c-darwin-x86_64.zip' ?><?cs
-set:ndk.mac64_bytes='772428792' ?><?cs
-set:ndk.mac64_checksum='4ce8e7ed8dfe08c5fe58aedf7f46be2a97564696' ?><?cs
+set:ndk.mac64_download='android-ndk-r12-darwin-x86_64.zip' ?><?cs
+set:ndk.mac64_bytes='734014148' ?><?cs
+set:ndk.mac64_checksum='708d4025142924f7097a9f44edf0a35965706737' ?><?cs
-set:ndk.linux64_download='android-ndk-r11c-linux-x86_64.zip' ?><?cs
-set:ndk.linux64_bytes='794135138' ?><?cs
-set:ndk.linux64_checksum='de5ce9bddeee16fb6af2b9117e9566352aa7e279' ?><?cs
+set:ndk.linux64_download='android-ndk-r12-linux-x86_64.zip' ?><?cs
+set:ndk.linux64_bytes='755431993' ?><?cs
+set:ndk.linux64_checksum='b7e02dc733692447366a2002ad17e87714528b39' ?><?cs
-set:ndk.win64_download='android-ndk-r11c-windows-x86_64.zip' ?><?cs
-set:ndk.win64_bytes='771407642' ?><?cs
-set:ndk.win64_checksum='3d89deb97b3191c7e5555f1313ad35059479f071' ?><?cs
-set:ndk.win32_download='android-ndk-r11c-windows-x86.zip' ?><?cs
-set:ndk.win32_bytes='728899082' ?><?cs
-set:ndk.win32_checksum='ff939bde6cd374eecbd2c3b2ad218697f9a5038c'
+set:ndk.win64_download='android-ndk-r12-windows-x86.zip' ?><?cs
+set:ndk.win64_bytes='706332762' ?><?cs
+set:ndk.win64_checksum='37fcd7acf6012d0068a57c1524edf24b0fef69c9' ?><?cs
+
+set:ndk.win32_download='android-ndk-r12-windows-x86_64.zip' ?><?cs
+set:ndk.win32_bytes='749444245' ?><?cs
+set:ndk.win32_checksum='80d64a77aab52df867ac55cec1e976663dd3326f'
?>
<?cs
def:size_in_mb(bytes)
diff --git a/docs/html/topic/libraries/data-binding/index.jd b/docs/html/topic/libraries/data-binding/index.jd
index ca8784e..293de51 100644
--- a/docs/html/topic/libraries/data-binding/index.jd
+++ b/docs/html/topic/libraries/data-binding/index.jd
@@ -18,7 +18,7 @@
<a href="#data_binding_layout_files">Data Binding Layout Files</a>
<ol>
<li>
- <a href="#writing_expressions">Writing your first data binding
+ <a href="#writing_expressions">Writing your first set of data binding
expressions</a>
</li>
@@ -29,9 +29,16 @@
<li>
<a href="#binding_data">Binding Data</a>
</li>
-
<li>
- <a href="#binding_events">Binding Events</a>
+ <a href="#event_handling">Event Handling</a>
+ <ol>
+ <li>
+ <a href="#method_references">Method References</a>
+ </li>
+ <li>
+ <a href="#listener_bindings">Listener Bindings</a>
+ </li>
+ </ol>
</li>
</ol>
</li>
@@ -147,27 +154,34 @@
application logic and layouts.
</p>
-<p>The Data Binding Library offers both flexibility and broad compatibility
-— it's a support library, so you can use it with all Android platform
-versions back to <strong>Android 2.1</strong> (API level 7+).</p>
+<p>
+ The Data Binding Library offers both flexibility and broad compatibility —
+ it's a support library, so you can use it with all Android platform versions
+ back to <strong>Android 2.1</strong> (API level 7+).
+</p>
-<p>To use data binding, Android Plugin for Gradle <strong>1.5.0-alpha1</strong>
-or higher is required.</p>
+<p>
+ To use data binding, Android Plugin for Gradle <strong>1.5.0-alpha1</strong>
+ or higher is required.
+</p>
<h2 id="build_environment">
Build Environment
</h2>
-<p>To get started with Data Binding, download the library from the Support
-repository in the Android SDK manager. </p>
-
<p>
-To configure your app to use data binding, add the <code>dataBinding</code> element to your
-<code>build.gradle</code> file in the app module.
+ To get started with Data Binding, download the library from the Support
+ repository in the Android SDK manager.
</p>
- <p>Use the following code snippet to configure data binding: </p>
+<p>
+ To configure your app to use data binding, add the <code>dataBinding</code>
+ element to your <code>build.gradle</code> file in the app module.
+</p>
+<p>
+ Use the following code snippet to configure data binding:
+</p>
<pre>
android {
....
@@ -176,13 +190,17 @@
}
}
</pre>
+<p>
+ If you have an app module that depends on a library which uses data binding,
+ your app module must configure data binding in its <code>build.gradle</code>
+ file as well.
+</p>
-<p>If you have an app module that depends on a library which uses data binding, your app module
- must configure data binding in its <code>build.gradle</code> file as well.</p>
-
-<p>Also, make sure you are using a compatible version of Android Studio.
-<strong>Android Studio 1.3</strong> and later provides support for data binding as described in
-<a href="#studio_support">Android Studio Support for Data Binding</a>.
+<p>
+ Also, make sure you are using a compatible version of Android Studio.
+ <strong>Android Studio 1.3</strong> and later provides support for data
+ binding as described in <a href="#studio_support">Android Studio Support for
+ Data Binding</a>.
</p>
<h2 id="data_binding_layout_files">
@@ -190,7 +208,7 @@
</h2>
<h3 id="writing_expressions">
- Writing your first data binding expressions
+ Writing your first set of data binding expressions
</h3>
<p>
@@ -223,20 +241,19 @@
The user <strong>variable</strong> within <strong>data</strong> describes a
property that may be used within this layout.
</p>
-
<pre>
<<strong>variable name="user" type="com.example.User"</strong>/>
</pre>
<p>
Expressions within the layout are written in the attribute properties using
- the “<code>@{}</code>” syntax. Here, the TextView’s text is set to the
- firstName property of user:
+ the “<code>&commat;{}</code>” syntax. Here, the TextView’s text is set to
+ the firstName property of user:
</p>
<pre>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@{user.firstName}"/>
+ android:text="&commat;{user.firstName}"/>
</pre>
<h3 id="data_object">
Data Object
@@ -261,7 +278,6 @@
to have data that is read once and never changes thereafter. It is also
possible to use a JavaBeans objects:
</p>
-
<pre>
public class User {
private final String firstName;
@@ -280,11 +296,12 @@
</pre>
<p>
From the perspective of data binding, these two classes are equivalent. The
- expression <strong><code>@{user.firstName}</code></strong> used for
- the TextView’s <strong><code>android:text</code></strong> attribute will
+ expression <strong><code>&commat;{user.firstName}</code></strong> used
+ for the TextView’s <strong><code>android:text</code></strong> attribute will
access the <strong><code>firstName</code></strong> field in the former class
- and the <code>getFirstName()</code> method in the latter class. Alternatively, it
- will also be resolved to <code>firstName()</code> if that method exists.
+ and the <code>getFirstName()</code> method in the latter class.
+ Alternatively, it will also be resolved to <code>firstName()</code> if that
+ method exists.
</p>
<h3 id="binding_data">
@@ -328,16 +345,38 @@
//or
ListItemBinding binding = DataBindingUtil.<em>inflate</em>(layoutInflater, R.layout.<em><strong>list_item</strong></em>, viewGroup, <strong>false</strong>);
</pre>
-
-<h3 id="binding_events">
- Binding Events
-</h3>
+<h3 id="event_handling">Event Handling</h3>
<p>
- Events may be bound to handler methods directly, similar to the way
- <strong><code>android:onClick</code></strong> can be assigned to a method in the Activity.
- Event attribute names are governed by the name of the listener method with a few exceptions.
- For example, {@link android.view.View.OnLongClickListener} has a method {@link android.view.View.OnLongClickListener#onLongClick onLongClick()},
- so the attribute for this event is <code>android:onLongClick</code>.
+Data Binding allows you to write expressions handling events that are dispatched from the views (e.g. onClick).
+Event attribute names are governed by the name of the listener method with a few exceptions.
+For example, {@link android.view.View.OnLongClickListener} has a method {@link android.view.View.OnLongClickListener#onLongClick onLongClick()},
+so the attribute for this event is <code>android:onLongClick</code>.
+There are two ways to handle an event.
+</p>
+<ul>
+ <li>
+ <a href="#method_references">Method References</a>: In your expressions, you can reference methods that conform to the signature of the listener method. When an expression evaluates to a method reference, Data Binding wraps the method reference and owner object in a listener, and sets that listener on the target view. If the expression evaluates to null, Data Binding does not create a listener and sets a null listener instead.
+ </li>
+ <li>
+ <a href="#listener_bindings">Listener Bindings</a>: These are lambda expressions that are evaluated when the event happens.
+Data Binding always creates a listener, which it sets on the view. When the event is dispatched, the listener evaluates the lambda expression.
+ </li>
+</ul>
+<h4 id="method_references">
+ Method References
+</h4>
+<p>
+ Events can be bound to handler methods directly, similar to the way
+ <strong><code>android:onClick</code></strong> can be assigned to a method in an Activity.
+ One major advantage compared to the {@code View#onClick} attribute is that the expression
+ is processed at compile time, so if the method does not exist or its signature is not
+ correct, you receive a compile time error.</p>
+<p>
+ The major difference between Method References and Listener Bindings is that
+ the actual listener implementation is created when the data is bound, not
+ when the event is triggered. If you prefer to evaluate the expression when
+ the event happens, you should use <a href="#listener_bindings">listener
+ binding</a>.
</p>
<p>
To assign an event to its handler, use a normal binding expression, with the value
@@ -345,7 +384,6 @@
</p>
<pre>public class MyHandlers {
public void onClickFriend(View view) { ... }
- public void onClickEnemy(View view) { ... }
}
</pre>
<p>
@@ -365,14 +403,121 @@
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"
- android:onClick="@{user.isFriend ? handlers.onClickFriend : handlers.onClickEnemy}"/>
- <TextView android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@{user.lastName}"
- android:onClick="@{user.isFriend ? handlers.onClickFriend : handlers.onClickEnemy}"/>
+ android:onClick="@{handlers::onClickFriend}"/>
</LinearLayout>
</layout>
</pre>
+<p>
+Note that the signature of the method in the expression must exactly match the signature of the method in the
+Listener object.
+</p>
+<h4 id="listener_bindings">
+ Listener Bindings
+</h4>
+<p>
+ Listener Bindings are binding expressions that run when an event happens.
+ They are similar to method references, but they let you run arbitrary data
+ binding expressions. This feature is available with Android Gradle Plugin for Gradle
+ version 2.0 and later.
+</p>
+<p>
+ In method references, the parameters of the method must
+ match the parameters of the event listener. In Listener Bindings, only your
+ return value must match the expected return value of the listener (unless it
+ is expecting void).
+ For example, you can have a presenter class that has the following method:
+</p>
+<pre>
+public class Presenter {
+ public void onSaveClick(Task task){}
+}
+</pre>
+ Then you can bind the click event to your class as follows:
+<pre>
+ <?xml version="1.0" encoding="utf-8"?>
+ <layout xmlns:android="http://schemas.android.com/apk/res/android">
+ <data>
+ <variable name="task" type="com.android.example.Task" />
+ <variable name="presenter" type="com.android.example.Presenter" />
+ </data>
+ <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent">
+ <Button android:layout_width="wrap_content" android:layout_height="wrap_content"
+ android:onClick="@{() -> presenter.onSaveClick(task)}" />
+ </LinearLayout>
+ </layout>
+</pre>
+<p>
+ Listeners are represented by lambda expressions that are allowed only as root
+ elements of your expressions. When a callback is used in an expression, Data
+ Binding automatically creates the necessary listener and registers for the
+ event. When the view fires the event, Data Binding evaluates the given
+ expression. As in regular binding expressions, you still get the null and
+ thread safety of Data Binding while these listener expressions are being
+ evaluated.
+</p>
+<p>
+ Note that in the example above, we haven't defined the {@code view} parameter
+ that is passed into {@link
+ android.view.View.OnClickListener#onClick(android.view.View view)}. Listener
+ bindings provide two choices for listener parameters: you can either ignore
+ all parameters to the method or name all of them. If you prefer to name the
+ parameters, you can use them in your expression. For example, the expression
+ above could be written as:
+</p>
+<pre>
+ android:onClick="@{(view) -> presenter.onSaveClick(task)}"
+</pre>
+Or if you wanted to use the parameter in the expression, it could work as follows:
+<pre>
+public class Presenter {
+ public void onSaveClick(View view, Task task){}
+}
+</pre>
+<pre>
+ android:onClick="@{(theView) -> presenter.onSaveClick(theView, task)}"
+</pre>
+You can use a lambda expression with more than one parameter:
+<pre>
+public class Presenter {
+ public void onCompletedChanged(Task task, boolean completed){}
+}
+</pre>
+<pre>
+ <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content"
+ android:onCheckedChanged="@{(cb, isChecked) -> presenter.completeChanged(task, isChecked)}" />
+</pre>
+<p>
+ If the event you are listening to returns a value whose type is not {@code
+ void}, your expressions must return the same type of value as well. For
+ example, if you want to listen for the long click event, your expression
+ should return {@code boolean}.
+</p>
+<pre>
+public class Presenter {
+ public boolean onLongClick(View view, Task task){}
+}
+</pre>
+<pre>
+ android:onLongClick="@{(theView) -> presenter.onLongClick(theView, task)}"
+</pre>
+<p>
+If the expression cannot be evaluated due to {@code null} objects, Data Binding returns
+the default Java value for that type. For example, {@code null} for reference types, {@code 0} for {@code int},
+{@code false} for {@code boolean}, etc.
+</p>
+<p>
+If you need to use an expression with a predicate (e.g. ternary), you can use
+{@code void} as a symbol.
+</p>
+<pre>
+ android:onClick="@{(v) -> v.isVisible() ? doSomething() : void}"
+</pre>
+
+<h5>Avoid Complex Listeners</h5>
+Listener expressions are very powerful and can make your code very easy to read.
+On the other hand, listeners containing complex expressions make your layouts hard to read and unmaintainable.
+These expressions should be as simple as passing available data from your UI to your callback method. You should implement
+any business logic inside the callback method that you invoked from the listener expression.
<p>
Some specialized click event handlers exist and they need an attribute other than
diff --git a/docs/html/training/articles/user-data-ids.jd b/docs/html/training/articles/user-data-ids.jd
index 5a4648b..9102166 100644
--- a/docs/html/training/articles/user-data-ids.jd
+++ b/docs/html/training/articles/user-data-ids.jd
@@ -189,15 +189,15 @@
<div style="padding:.5em 2em;">
<div style="border-left:4px solid #999;padding:0 1em;font-style:italic;">
-<p>...upon reset, a new advertising
+<p>...if reset, a new advertising
identifier must not be connected to a previous advertising identifier or data
derived from a previous advertising identifier without the explicit consent
- of the user</span></p>
+ of the user.</span></p>
</div>
</div>
<p>
- <em><strong>Always respect the associated Interest Based Advertising
+ <em><strong>Always respect the associated Personalized Ads
flag</strong></em>. Advertising IDs are configurable in that users can limit
the amount of tracking associated with the ID. Always use the <code><a href=
"https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.Info.html#isLimitAdTrackingEnabled()">
@@ -210,10 +210,10 @@
<div style="padding:.5em 2em;">
<div style="border-left:4px solid #999;padding:0 1em;font-style:italic;">
-<p>...you must abide by a user’s ‘opt out of
- interest-based advertising’ setting. If a user has enabled this setting, you
+<p>...you must abide by a user’s ‘Opt out of interest-based advertising’ or 'Opt
+ out of Ads Personalization' setting. If a user has enabled this setting, you
may not use the advertising identifier for creating user profiles for
- advertising purposes or for targeting users with interest-based advertising.
+ advertising purposes or for targeting users with personalized advertising.
Allowed activities include contextual advertising, frequency capping,
conversion tracking, reporting and security and fraud detection.</span></p>
</div>
@@ -286,7 +286,8 @@
<code>account_id</code> column in both tables, which would be a violation of
the <a href=
"https://play.google.com/about/developer-content-policy.html">Google Play
- Developer Content Policy</a>.
+ Developer Content Policy</a>, if you did not get explicit permission from
+ your users.
</p>
<p>
diff --git a/docs/html/training/auto/audio/index.jd b/docs/html/training/auto/audio/index.jd
index aa20e3a..3a1b1e88 100644
--- a/docs/html/training/auto/audio/index.jd
+++ b/docs/html/training/auto/audio/index.jd
@@ -21,6 +21,7 @@
<li><a href="#config_manifest">Configure Your Manifest</a></li>
<li><a href="#isconnected">Determine if Your App is Connected</a></li>
<li><a href="#alarm">Handle Alarms</a></li>
+ <li><a href="#mediaadv">Handle Media Advertisements</a></li>
<li><a href="#implement_browser">Build a Browser Service</a></li>
<li><a href="#implement_callback">Implement Play Controls</a></li>
<li><a href="#support_voice">Support Voice Actions</a></li>
@@ -261,7 +262,7 @@
<ul>
<li>Disable the alarm.</li>
<li>Play the alarm over
-<a href="{@docRoot}reference/android/media/AudioManager.html">STREAM_ALARM</a>,
+<a href="{@docRoot}reference/android/media/AudioManager.html#STREAM_ALARM">STREAM_ALARM</a>,
and provide a UI on the phone screen to disable the alarm.</li>
</ul>
@@ -279,6 +280,33 @@
}
</pre>
+<h2 id="mediaadv">Handle Media Advertisements</h2>
+<p>By default, Android Auto displays a notification when
+the media metadata changes during an audio playback session. When a media
+app switches from playing music to running an advertisement, it is distracting
+(and unnecessary) to display a notification to the user. To prevent Android Auto
+from displaying a notification in this case, you must set the media metadata
+key {@code android.media.metadata.ADVERTISEMENT} to 1, as shown in the code
+snippet below:
+
+<pre>
+
+@Override
+public static final String EXTRA_METADATA_ADVERTISEMENT =
+ "android.media.metadata.ADVERTISEMENT";
+
+public void onPlayFromMediaId(String mediaId, Bundle extras) {
+ MediaMetadata.Builder builder = new MediaMetadata.Builder();
+ // ...
+ if (isAd(mediaId)) {
+ builder.putLong(EXTRA_METADATA_ADVERTISEMENT, 1);
+ }
+ // ...
+ mediaSession.setMetadata(builder.build());
+}
+
+</pre>
+
<h2 id="implement_browser">Build a Browser Service</h2>
<p>Auto devices interact with your app by contacting its implementation of a
diff --git a/docs/html/training/material/animations.jd b/docs/html/training/material/animations.jd
index 9c78545..96cc5a1 100644
--- a/docs/html/training/material/animations.jd
+++ b/docs/html/training/material/animations.jd
@@ -415,12 +415,16 @@
</selector>
</pre>
-<p>To attach custom view state animations to a view, define an animator using the
-<code>selector</code> element in an XML resource file as in this example, and assign it to your
-view with the <code>android:stateListAnimator</code> attribute. To assign a state list animator
-to a view in your code, use the {@link android.animation.AnimatorInflater#loadStateListAnimator
-AnimationInflater.loadStateListAnimator()} method, and assign the animator to your view with the
-{@link android.view.View#setStateListAnimator View.setStateListAnimator()} method.</p>
+<p>
+ To attach custom view state animations to a view, define an animator using
+ the <code>selector</code> element in an XML resource file as in this example,
+ and assign it to your view with the <code>android:stateListAnimator</code>
+ attribute. To assign a state list animator to a view in your code, use the
+ {@link android.animation.AnimatorInflater#loadStateListAnimator
+ AnimatorInflater.loadStateListAnimator()} method, and assign the animator to
+ your view with the {@link android.view.View#setStateListAnimator
+ View.setStateListAnimator()} method.
+</p>
<p>When your theme extends the material theme, buttons have a Z animation by default. To avoid this
behavior in your buttons, set the <code>android:stateListAnimator</code> attribute to
diff --git a/docs/html/training/testing/start/index.jd b/docs/html/training/testing/start/index.jd
index 707ba9d8..aa0473f 100644
--- a/docs/html/training/testing/start/index.jd
+++ b/docs/html/training/testing/start/index.jd
@@ -9,51 +9,20 @@
<div id="tb">
<h2>
- Dependencies and prerequisites
- </h2>
-
- <ul>
- <li>
- <a href="{@docRoot}tools/studio/index.html">Android Studio 2.0</a>, or
- later.
- </li>
-
- <li>The Android Support Repository (available from the <a href=
- "{@docRoot}tools/help/sdk-manager.html">SDK Manager</a>)
- </li>
- </ul>
-
- <h2>
- This lesson teaches you to
+ In this document
</h2>
<ol>
- <li>
- <a href="#config-local-tests">Configure Your Project for Local Unit
- Tests</a>
- </li>
-
- <li>
- <a href="#config-instrumented-tests">Configure Your Project for
- Instrumented Tests</a>
- </li>
-
- <li>
- <a href="#build">Build and Run Your Tests</a>
+ <li><a href="#test-types">Test Types</a></li>
+ <li><a href="#test-apis">Test APIs</a>
<ol>
- <li>
- <a href="#run-local-tests">Run Local Unit Tests</a>
- </li>
-
- <li>
- <a href="#run-instrumented-tests">Run Instrumented Tests</a>
- </li>
-
- <li>
- <a href="#run-ctl">Run Instrumented Tests with Cloud Test Lab</a>
- </li>
+ <li><a href="#junit">JUnit</a></li>
+ <li><a href="#support-library">Android Testing Support Library</a></li>
+ <li><a href="#assertion">Assertion classes</a></li>
+ <li><a href="#monkeyrunner">Monkey and monkeyrunner</a></li>
</ol>
</li>
+ <li><a href="#build">Guides for Building Android Tests</a>
</ol>
<h2>
@@ -61,10 +30,6 @@
</h2>
<ul>
- <li>
- <a href="{@docRoot}tools/testing/testing_android.html">Testing
- Concepts</a>
- </li>
<li>
<a href="https://github.com/googlesamples/android-testing" class=
@@ -80,484 +45,356 @@
</div>
<p>
- Writing and running tests are important parts of the Android app development
- cycle. Well-written tests can help you catch bugs early in development and
- give you confidence in your code. Using Android Studio, you can run local
- unit tests or instrumented tests on a variety of physical or virtual Android
- devices. You can then analyze the results and make changes to your code
- without leaving the development environment.
+ Android tests are based on <a href="http://junit.org/" class=
+ "external-link">JUnit</a>, and you can run them either as local
+ unit tests on the JVM or as instrumented tests on an Android device.
+ This page provides an introduction to the concepts and
+ tools for building Android tests.
</p>
-<p>
- <em>Local unit tests</em> are tests that run on your local machine, without
- needing access to the Android framework or an Android device. To learn how to
- develop local units tests, see <a href=
- "{@docRoot}training/testing/unit-testing/local-unit-tests.html">Building
- Local Unit Tests</a>.
-</p>
-<p>
- <em>Instrumented tests</em> are tests that run on an Android device or
- emulator. These tests have access to {@link android.app.Instrumentation}
- information, such as the {@link android.content.Context} for the app under
- test. Instrumented tests can be used for unit, user interface (UI), or app
- component integration testing. To learn how to develop instrumented tests for
- your specific needs, see these additional topics:
-</p>
+<h2 id="test-types">Test Types</h2>
+
+
+<p>When using Android Studio to write any of your tests, your test code must go
+into one of two different code directories (source sets). For each module in
+your project, Android Studio includes both source sets, corresponding to the
+following test types:</p>
+
+<dl>
+<dt><b>Local unit tests</b></dt>
+<dd>Located at <code><var>module-name</var>/src/test/java/</code>.
+<p>These tests run on the local JVM
+and do not have access to functional Android framework APIs.</p>
+<p>To get started, see <a
+href="/training/testing/unit-testing/local-unit-tests.html">Building Local
+Unit Tests</a>.</p>
+</dd>
+
+<dt><b>Instrumented tests</b></dt>
+<dd>Located at <code><var>module-name</var>/src/androidTest/java/</code>.
+<p>These are all tests that must run on an Android hardware device or
+an Android emulator.</p>
+
+<p>Instrumented tests are built into an APK that runs on the device alongside
+your app under test. The system runs your test APK and your app under tests in
+the same process, so your tests can invoke methods and modify fields in the
+app, and automate user interaction with your app.</p>
+
+<p>For information about how to create instrumented tests, see the
+following topics:</p>
<ul>
<li>
<a href=
- "{@docRoot}training/testing/unit-testing/instrumented-unit-tests.html">Building
- Instrumented Unit Tests</a> - Build more complex unit tests that have
- Android dependencies which cannot be easily filled by using mock objects.
+ "{@docRoot}training/testing/unit-testing/instrumented-unit-tests.html"
+ >Building Instrumented Unit Tests</a>: Build complex unit tests with
+ Android dependencies that cannot be satisfied with mock objects.
</li>
<li>
<a href="{@docRoot}training/testing/ui-testing/index.html">Automating User
- Interface Tests</a> - Create tests to verify that the user interface
+ Interface Tests</a>: Create tests to verify that the user interface
behaves correctly for user interactions within a single app or for
interactions across multiple apps.
</li>
<li>
<a href="{@docRoot}training/testing/integration-testing/index.html">Testing
- App Component Integrations</a> - Verify the behavior of components that
+ App Component Integrations</a>: Verify the behavior of components that
users do not directly interact with, such as a <a href=
"{@docRoot}guide/components/services.html">Service</a> or a <a href=
- "guide/topics/providers/content-providers.html">Content Provider</a>.
+ "{@docRoot}guide/topics/providers/content-providers.html">Content Provider</a>.
</li>
</ul>
-<p>
- This lesson teaches you how to build and run your tests using using Android
- Studio. If you are not using Android Studio, you can learn how to
- <a href="{@docRoot}tools/testing/testing_otheride.html">run your tests from
- the command-line</a>.
-</p>
+</dd>
+</dl>
-<h3 id="config-local-tests">
- Configure Your Project for Local Unit Tests
-</h3>
+<img src="/images/testing/test-types_2x.png" alt="" width="798" />
-<p>
- In your Android Studio project, you must store the source files for local
- unit tests under a specific source directory ({@code src/test/java}). This
- improves project organization by grouping your unit tests together into a
- single source set.
-</p>
-
-<p>
- As with production code, you can create local unit tests for a <a href=
- "{@docRoot}tools/building/configuring-gradle.html#workBuildVariants">specific
- flavor or build type</a>. Keep your unit tests in a test source tree location
- that corresponds to your production source tree, such as:
-</p>
+<p>However, the <em>local unit tests</em> and <em>instrumented tests</em>
+described above are just terms that help distinguish the tests that run on your
+local JVM from the tests that run on the Android platform (on a hardware device
+or emulator). The real testing types that you should understand when building a
+complete test suite are described in the following table.</p>
<table>
-<tr>
-<th>Path to Production Class</th>
-<th>Path to Local Unit Test Class</th>
-</tr>
-<tr>
-<td>{@code src/main/java/Foo.java}</td>
-<td>{@code src/test/java/FooTest.java}</td>
-</tr>
-<tr>
-<td>{@code src/debug/java/Foo.java}</td>
-<td>{@code src/testDebug/java/FooTest.java}</td>
-</tr>
-<tr>
-<td>{@code src/myFlavor/java/Foo.java}</td>
-<td>{@code src/testMyFlavor/java/FooTest.java}</td>
-</tr>
+ <tr>
+ <th>
+ Type
+ </th>
+ <th>
+ Subtype
+ </th>
+ <th>
+ Description
+ </th>
+ </tr>
+
+ <tr>
+ <td rowspan="3">
+ Unit tests
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ Local Unit Tests
+ </td>
+ <td>
+ Unit tests that run locally on the Java Virtual Machine (JVM). Use these
+tests to minimize execution time when your tests have no Android framework
+dependencies or when you can mock the Android framework dependencies.
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ Instrumented unit tests
+ </td>
+ <td>
+ Unit tests that run on an Android device or emulator. These tests have
+access to <code><a href=
+"/reference/android/app/Instrumentation.html">Instrumentation</a></code>
+information, such as the <code><a href=
+"/reference/android/content/Context.html">Context</a></code> of the app you are
+testing. Use these tests when your tests have Android dependencies that mock
+objects cannot satisfy.
+ </td>
+ </tr>
+
+ <tr>
+ <td style="white-space:nowrap" rowspan="3">
+ Integration Tests
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ Components within your app only
+ </td>
+ <td>
+ This type of test verifies that the target app behaves as expected when
+a user performs a specific action or enters a specific input in its activities.
+For example, it allows you to check that the target app returns the correct UI
+output in response to user interactions in the app’s activities. UI testing
+frameworks like <a href=
+ "/tools/testing-support-library/index.html#Espresso">Espresso</a> allow
+you to programmatically simulate user actions and test complex intra-app user
+interactions.
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ Cross-app Components
+ </td>
+ <td>
+ This type of test verifies the correct behavior of interactions between
+different user apps or between user apps and system apps. For example, you might
+want to test that your app behaves correctly when the user performs an action
+in the Android Settings menu. UI testing frameworks that support cross-app
+interactions, such as <a
+href="/topic/libraries/testing-support-library/index.html#UIAutomator"
+>UI Automator</a>, allow you to create tests for such scenarios.
+ </td>
+ </tr>
</table>
-<p>
- You'll need to configure the testing dependencies for your project to use the
- standard APIs provided by the JUnit 4 framework. If your test needs to
- interact with Android dependencies, include the <a href=
- "https://github.com/mockito/mockito" class="external-link">Mockito</a>
- library to simplify your local unit tests. To learn more about using mock
- objects in your local unit tests, see <a href=
- "{@docRoot}training/testing/unit-testing/local-unit-tests.html#mocking-dependencies">
- Mocking Android dependencies</a>.
-</p>
-<p>
- In your app's top-level {@code build.gradle} file, you need to specify these
- libraries as dependencies:
-</p>
+
+
+
+
+<h2 id="test-apis">Test APIs</h2>
+
+<p>The following are common APIs used for testing apps on Android.</p>
+
+
+<h3 id="junit">JUnit</h3>
+
+<p>You should write your unit or integration test class as a <a href=
+"http://junit.org/" class="external-link">JUnit 4</a> test class. The framework
+offers a convenient way to perform common setup, teardown, and assertion
+operations in your test.</p>
+
+<p>A basic JUnit 4 test class is a Java class that contains one or more test
+methods. A test method begins with the <code>@Test</code> annotation and
+contains the code to exercise and verify a single functionality (that is, a
+logical unit) in the component that you want to test.</p>
+
+<p>The following snippet shows an example JUnit 4 integration test that uses the
+<a href="/topic/libraries/testing-support-library/index.html#Espresso">Espresso
+APIs</a> to perform a click action on a UI element, then checks to see if
+an expected string is displayed.</p>
<pre>
-dependencies {
- // Required -- JUnit 4 framework
- testCompile 'junit:junit:4.12'
- // Optional -- Mockito framework
- testCompile 'org.mockito:mockito-core:1.10.19'
-}
-</pre>
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class MainActivityInstrumentationTest {
-<h3 id="config-instrumented-tests">
- Configure Your Project for Instrumented Tests
-</h3>
+ @Rule
+ public ActivityTestRule mActivityRule = new ActivityTestRule<>(
+ MainActivity.class);
-<p>
- In your Android Studio project, you must place the source code for your
- instrumentated tests under a specific directory
- (<code>src/androidTest/java</code>).
-</p>
+ @Test
+ public void sayHello(){
+ onView(withText("Say hello!")).perform(click());
-<p>
- <a href="{@docRoot}tools/testing-support-library/index.html#setup">Download
- the Android Testing Support Library Setup</a>, which provides APIs that allow
- you to quickly build and run instrumented test code for your apps. The
- Testing Support Library includes a JUnit 4 test runner (<a href=
- "{@docRoot}tools/testing-support-library/index.html#AndroidJUnitRunner">AndroidJUnitRunner</a>
- ) and APIs for functional UI tests (<a href=
- "{@docRoot}tools/testing-support-library/index.html#Espresso">Espresso</a>
- and <a href=
- "{@docRoot}tools/testing-support-library/index.html#UIAutomator">UI
- Automator</a>).
-</p>
-
-<p>
- You'll need to configure the Android testing dependencies for your project to
- use the test runner and the rules APIs provided by the Testing Support
- Library. To simplify your test development, we also recommend that you
- include the <a href="https://github.com/hamcrest" class=
- "external-link">Hamcrest</a> library, which lets you create more flexible
- assertions using the Hamcrest matcher APIs.
-</p>
-
-<p>
- In your app's top-level {@code build.gradle} file, you need to specify these
- libraries as dependencies:
-</p>
-
-<pre>
-dependencies {
- androidTestCompile 'com.android.support:support-annotations:23.0.1'
- androidTestCompile 'com.android.support.test:runner:0.4.1'
- androidTestCompile 'com.android.support.test:rules:0.4.1'
- // Optional -- Hamcrest library
- androidTestCompile 'org.hamcrest:hamcrest-library:1.3'
- // Optional -- UI testing with Espresso
- androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'
- // Optional -- UI testing with UI Automator
- androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.1'
-}
-</pre>
-
-
-<p>
- To use JUnit 4 test classes, make sure to specify <a href=
- "{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code
- AndroidJUnitRunner}</a> as the default test instrumentation runner in your
- project by including the following setting in your app's module-level {@code build.gradle}
- file:
-</p>
-
-<pre>
-android {
- defaultConfig {
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ onView(withId(R.id.textView)).check(matches(withText("Hello, World!")));
}
}
</pre>
-<h3 id="testartifacts">Work With Test Artifacts</h3>
-<p>Android Studio has two types of test artifacts: Android Instrumentation Tests
-and Unit Tests. Previously, you could work with just one test artifact at a
-time. Now, both test artifacts are enabled.
-The advantage of enabling both test artifacts is that any changes you make to
-the underlying code affect
-them both. For example, if you rename a class that both test artifacts access,
-both will know about the class name refactoring.</p>
-
-<p>The figure shows what your project looks like with both test
-artifacts enabled. Notice the shading of both test artifacts.</p>
-
-<!-- Commenting out for now, but leaving it in case we need to add it back.
-<img src="{@docRoot}images/training/testartifactseparate.png" style="float:left;width:250px;margin-right:20px" /> -->
-<img src="{@docRoot}images/training/testartifactcombined.png" style="float:left;width:250px" />
-<!-- Commenting out for now, but leaving it in case we need to add it back.
-<p>
-By default, both test artifacts are enabled in Android Studio. To enable just
-one, deselect <strong>Enable all test artifacts</strong> in your preferences:
-</p>
-
-<ol>
-<li>Select
-<strong>Android Studio</strong> > <strong>Preferences</strong> > <strong>Build,
-Execution, Deployment</strong> > <strong>Build Tools</strong> >
-<strong>Gradle</strong> > <strong>Experimental</strong>.</li>
-<li>Deselect the test artifacts option.</li>
-<li>Click <strong>OK</strong>.</li>
-</ol>
--->
-
-<h2 id="build">Build and Run Your Tests</h2>
-
-
-<p>
- Android Studio provides all the tools you need to build, run, and analyze
- your tests within the development environment. You can also run instrumented
- tests on multiple device configurations, simultaneously, using <a href=
- "https://developers.google.com/cloud-test-lab/">Cloud Test Lab</a>
- integration.
-</p>
-
-<p class="note">
- <strong>Note:</strong> While running or debugging instrumented tests,
- Android Studio does not inject the additional methods required for <a href=
- "{@docRoot}tools/building/building-studio.html#instant-run">Instant Run</a>
- and turns the feature off.
-</p>
-
-<h3 id="run-local-tests">
- Run Local Unit Tests
-</h3>
-
-<p>
- To run your local unit tests:
-</p>
-
-<ol>
-
- <li>In the <em>Project</em> window, right click on the project and
- synchronize your project.
- </li>
-
- <!--
-<li>If you enabled one test artifact only, open the
-<strong>Build Variants</strong> window by clicking the left-hand tab, then
-change the test artifact to <em>Unit Tests</em>.
-</li>
--->
-
- <li>In the <em>Project</em> window, navigate to your unit test class or
- method, then right-click it and select <strong>Run</strong> <img src=
- "{@docRoot}images/tools/as-run.png" alt="" style=
- "vertical-align:bottom;margin:0;">.
- <ul>
- <li>To run all tests in the unit test directory, right-click on the
- directory and select <strong>Run tests</strong> <img src=
- "{@docRoot}images/tools/as-run.png" alt="" style=
- "vertical-align:bottom;margin:0;">.
- </li>
- </ul>
- </li>
-
-</ol>
-
-<p>
- The Android Plugin for Gradle compiles the local unit test code located in
- the default directory ({@code src/test/java}), builds a test app, and
- executes it locally using the default test runner class. Android Studio then
- displays the results in the <em>Run</em> window.
-</p>
-
-<h3 id="run-instrumented-tests">
- Run Instrumented Tests
-</h3>
-
-<p>
- To run your instrumented tests:
-</p>
+<p>In your JUnit 4 test class, you can call out sections in your test code for
+special processing by using the following annotations:</p>
<ul>
- <!--
-<li>If you enabled one test artifact only, open the
-<strong>Build Variants</strong> window by clicking the left-hand tab, then set
-the test artifact to <em>Android Instrumentation Tests</em>.
-</li>
--->
+<li><code>@Before</code>: Use this annotation to specify a block of code that
+contains test setup operations. The test class invokes this code block before
+each test. You can have multiple <code>@Before</code> methods but the order in
+which the test class calls these methods is not guaranteed.</li>
- <li>In the <em>Project</em> window, navigate to your instrumented test class
- or method, then right-click and run it using the Android Test configuration.
- To run all tests in the instrumented test directory, right-click the
- directory and select <strong>Run tests</strong> <img src=
- "{@docRoot}images/tools/as-run.png" alt="" style=
- "vertical-align:bottom;margin:0;">.
- </li>
+<li><code>@After</code>: This annotation specifies a block of code that
+contains test tear-down operations. The test class calls this code block after
+every test method. You can define multiple <code>@After</code> operations in
+your test code. Use this annotation to release any resources from memory.</li>
+
+<li><code>@Test</code>: Use this annotation to mark a test method. A single
+test class can contain multiple test methods, each prefixed with this
+annotation.</li>
+
+<li><code>@Rule</code>: Rules allow you to flexibly add or redefine the
+behavior of each test method in a reusable way. In Android testing, use this
+annotation together with one of the test rule classes that the Android Testing
+Support Library provides, such as <a href=
+"/reference/android/support/test/rule/ActivityTestRule.html"><code>ActivityTestRule</code></a>
+or <a href=
+"/reference/android/support/test/rule/ServiceTestRule.html"><code>ServiceTestRule</code></a>.</li>
+
+<li><code>@BeforeClass</code>: Use this annotation to specify static methods
+for each test class to invoke only once. This testing step is useful for
+expensive operations such as connecting to a database.</li>
+
+<li><code>@AfterClass</code>: Use this annotation to specify static methods for
+the test class to invoke only after all tests in the class have run. This
+testing step is useful for releasing any resources allocated in the
+<code>@BeforeClass</code> block.</li>
+
+<li><code>@Test(timeout=)</code>: Some annotations support the ability to pass
+in elements for which you can set values. For example, you can specify a
+timeout period for the test. If the test starts but does not complete within
+the given timeout period, it automatically fails. You must specify the timeout
+period in milliseconds, for example: <code>@Test(timeout=5000)</code>.</li>
</ul>
-<p>
- The <a href="{@docRoot}tools/building/plugin-for-gradle.html">Android Plugin
- for Gradle</a> compiles the instrumented test code located in the default
- directory ({@code src/androidTest/java}), builds a test APK and production
- APK, installs both APKs on the connected device or emulator, and runs the
- tests. Android Studio then displays the results of the instrumented test execution in the
- <em>Run</em> window.
+<p>For more annotations, see the documentation for <a
+href="http://junit.sourceforge.net/javadoc/org/junit/package-summary.html"
+class="external-link">JUnit annotations</a> and the <a
+href="/reference/android/support/annotation/package-summary.html">Android
+annotations</a>.</p>
+
+<p>Use the JUnit <code><a href=
+"/reference/junit/framework/Assert.html">Assert</a></code> class to verify the
+correctness of an object's state. The assert methods compare values you expect
+from a test to the actual results and throw an exception if the comparison
+fails. <a href="#AssertionClasses">Assertion classes</a> describes these
+methods in more detail.</p>
+
+
+<h3 id="support-library">Android Testing Support Library</h3>
+
+<p>The <a href="/topic/libraries/testing-support-library/index.html">Android
+Testing Support Library</a> provides a set of APIs that allow you
+to quickly build and run test code for your apps, including JUnit 4 and
+functional UI tests. The library includes the following instrumentation-based
+APIs that are useful when you want to automate your tests:</p>
+
+<dt><a href="/topic/libraries/testing-support-library/index.html#AndroidJUnitRunner"
+>AndroidJUnitRunner</a></dt>
+<dd>A JUnit 4-compatible test runner for Android.</dd>
+
+<dt><a href="/topic/libraries/testing-support-library/index.html#Espresso"
+>Espresso</a></dt>
+<dd>A UI testing framework; suitable for functional UI testing within an
+app.</dd>
+
+<dt><a href="/topic/libraries/testing-support-library/index.html#UIAutomator"
+>UI Automator</a></dt>
+<dd>A UI testing framework suitable for cross-app functional UI testing between
+both system and installed apps.</dd>
+
+
+<h3 id="assertion">Assertion classes</h3>
+
+<p>Because Android Testing Support Library APIs extend JUnit, you can use
+assertion methods to display the results of tests. An assertion method compares
+an actual value returned by a test to an expected value, and throws an
+AssertionException if the comparison test fails. Using assertions is more
+convenient than logging, and provides better test performance.</p>
+
+<p>To simplify test development, you should use the <a href=
+"https://github.com/hamcrest" class="external-link">Hamcrest library</a>, which
+lets you create more flexible tests using the Hamcrest matcher APIs.</p>
+
+
+
+<h3 id="monkeyrunner">Monkey and monkeyrunner</h3>
+
+<p>The Android SDK includes two tools for functional-level app testing:</p>
+
+<dl>
+<dt>Monkey</dt>
+<dd>This is a command-line tool that sends pseudo-random streams of keystrokes,
+touches, and gestures to a device. You run it with the <a href=
+"/studio/command-line/adb.html">Android Debug Bridge (adb)</a> tool, and use it
+to stress-test your app, report back errors any that are encountered, or repeat
+a stream of events by running the tool multiple times with the same random
+number seed.</dd>
+
+
+<dt>monkeyrunner</dt>
+<dd>This tool is an API and execution environment for test programs written in
+Python. The API includes functions for connecting to a device, installing and
+uninstalling packages, taking screenshots, comparing two images, and running a
+test package against an app. Using the API, you can write a wide range of
+large, powerful, and complex tests. You run programs that use the API with the
+<code>monkeyrunner</code> command-line tool.</dd>
+</dl>
+
+
+
+
+<h2 id="build">Guides for Building Android Tests</h2>
+
+<p>The following documents provide more detail about how to build and run
+a variety of test types:
</p>
-<h3 id="run-ctl">Run Instrumented Tests with Cloud Test Lab</h3>
-
-<p>
- Using <a href="https://developers.google.com/cloud-test-lab/">Cloud Test
- Lab</a>, you can simultaneously test your app on many popular Android
- devices, across multiple languages, screen orientations, and versions of the
- Android platform. These tests run on actual physical devices in remote Google
- data centers. You can also <a href=
- "https://developers.google.com/cloud-test-lab/test-screenshots">configure
- your instrumented tests to take screenshots</a> while Cloud Test Lab runs its
- tests. You can <a href=
- "https://developers.google.com/cloud-test-lab/command-line">deploy tests to
- Cloud Test Lab from the command line</a>, or from Android Studio's integrated
- testing tools.
-</p>
-
-<p>
- Android Studio allows you to connect to your Google Cloud Platform account,
- configure your tests, deploy them to Cloud Test Lab, and analyze the results
- all within the development environment. Cloud Test Lab in Android Studio
- supports the following Android test frameworks: <a href=
- "{@docRoot}training/testing/ui-testing/espresso-testing.html">Espresso</a>,
- <a href="{@docRoot}tools/testing-support-library/index.html#UIAutomator">UI
- Automator 2.0</a>, or <a class="external-link" href=
- "https://github.com/robotiumtech/robotium">Robotium</a>. Test results provide
- test logs and include the details of any app failures.
-</p>
-
-<p>
- Before you can start using Cloud Test Lab, you need to:
-</p>
-
-<ol>
- <li>
- <a href="https://console.developers.google.com/freetrial">Create a
- Google Cloud Platform account</a> to use with active billing.
- </li>
-
- <li>
- <a href="https://support.google.com/cloud/answer/6251787">Create a Google
- Cloud project</a> for your app.
- </li>
-
- <li>
- <a href="https://support.google.com/cloud/answer/6288653">Set up an active
- billing account</a> and associate it with the project you just created.
- </li>
-</ol>
-
-
-<h4 id="configure-matrix">
-Configure a test matrix and run a test
-</h4>
-
-<p>
- Android Studio provides integrated tools that allow you to configure how you
- want to deploy your tests to Cloud Test Lab. After you have created a Google
- Cloud project with active billing, you can create a test configuration and
- run your tests:
-</p>
-
-<ol>
- <li>Click <strong>Run</strong> > <strong>Edit Configurations</strong> from
- the main menu.
- </li>
-
- <li>Click <strong>Add New Configuration (+)</strong> and select
- <strong>Android Tests</strong>.
- </li>
-
- <li>In the Android Test configuration dialog:
- <ol type="a">
- <li>Enter or select the details of your test, such as the test name, module
- type, test type, and test class.
- </li>
-
- <li>From the <em>Target</em> drop-down menu under <em>Deployment Target
- Options</em>, select <strong>Cloud Test Lab Device Matrix</strong>.
- </li>
-
- <li>If you are not logged in, click <strong>Connect to Google Cloud
- Platform</strong> and allow Android Studio access to your account.
- </li>
-
- <li>Next to <em>Cloud Project</em>, click the <img src=
- "{@docRoot}images/tools/as-wrench.png" alt="wrench and nut" style=
- "vertical-align:bottom;margin:0;"> button and select your Google Cloud
- Platform project from the list.
- </li>
- </ol>
- </li>
-
- <li>Create and configure a test matrix:
- <ol type="a">
- <li>Next to the <em>Matrix Configuration</em> drop-down list, click <strong>
- Open Dialog</strong> <img src="{@docRoot}images/tools/as-launchavdm.png"
- alt="ellipses button" style="vertical-align:bottom;margin:0;">.
- </li>
-
- <li>Click <strong>Add New Configuration (+)</strong>.
- </li>
-
- <li>In the <strong>Name</strong> field, enter a name for your new
- configuration.
- </li>
-
- <li>Select the device(s), Android version(s), locale(s) and screen
- orientation(s) that you want to test your app with. Cloud Test Lab will test
- your app against every combination of your selections when generating test
- results.
- </li>
-
- <li>Click <strong>OK</strong> to save your configuration.
- </li>
- </ol>
- </li>
-
- <li>Click <strong>OK</strong> in the <em>Run/Debug Configurations</em> dialog
- to exit.
- </li>
-
- <li>Run your tests by clicking <strong>Run</strong> <img src=
- "{@docRoot}images/tools/as-run.png" alt="" style=
- "vertical-align:bottom;margin:0;">.
- </li>
-</ol>
-
-<img src="{@docRoot}images/training/ctl-config.png" alt="">
-<p class="img-caption">
- <strong>Figure 1.</strong> Creating a test configuration for Cloud Test
- Lab.
-</p>
-
-<h4 id="ctl-results">
- Analyzing test results
-</h4>
-
-<p>
- When Cloud Test Lab completes running your tests, the <em>Run</em> window will
- open to show the results, as shown in figure 2. You may need to click
- <strong>Show Passed</strong> <img src="{@docRoot}images/tools/as-ok.png" alt=
- "" style="vertical-align:bottom;margin:0;"> to see all your executed tests.
-</p>
-
-<img src="{@docRoot}images/training/ctl-test-results.png" alt="">
-
-<p class="img-caption">
- <strong>Figure 2.</strong> Viewing the results of instrumented tests using
- Cloud Test Lab.
-</p>
-
-<p>
- You can also analyze your tests on the web by following the link displayed at
- the beginning of the test execution log in the <em>Run</em> window, as shown
- in figure 3.
-</p>
-
-<img src="{@docRoot}images/training/ctl-exec-log.png" alt="">
-
-<p class="img-caption">
- <strong>Figure 3.</strong> Click the link to view detailed test results on
- the web.
-</p>
-
-<p>
- To learn more about interpreting web results, see <a href=
- "https://developers.google.com/cloud-test-lab/analyzing-results">Analyzing
- Cloud Test Lab Web Results</a>.
-</p>
\ No newline at end of file
+<dl>
+ <dt><a href="/training/testing/unit-testing/local-unit-tests.html"
+ >Building Local Unit Tests</a></dt>
+ <dd>Build unit tests that have no dependencies or only simple dependencies
+ that you can mock, which run on your local JVM.</dd>
+ <dt><a href=
+ "/training/testing/unit-testing/instrumented-unit-tests.html"
+ >Building Instrumented Unit Tests</a></dt>
+ <dd>Build complex unit tests with
+ Android dependencies that cannot be satisfied with mock objects,
+ which run on a hardware device or emulator.</dd>
+ <dt><a href="/training/testing/ui-testing/index.html">Automating User
+ Interface Tests</a></dt>
+ <dd>Create tests to verify that the user interface
+ behaves correctly for user interactions within a single app or for
+ interactions across multiple apps.</dd>
+ <dt><a href="/training/testing/integration-testing/index.html">Testing App
+ Compontent Integrations</a></dt>
+ <dd>Verify the behavior of components that
+ users do not directly interact with, such as a service or a content
+ provider.</dd>
+ <dt><a href="/training/testing/performance.html">Testing Display
+ Performance</a></dt>
+ <dd>Write tests that measure your app's UI performance to ensure
+ a consistently smooth user experience.</dd>
+</dl>
\ No newline at end of file
diff --git a/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd b/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd
index 38321ee..f65766d 100644
--- a/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd
+++ b/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd
@@ -7,21 +7,20 @@
<!-- This is the training bar -->
<div id="tb-wrapper">
<div id="tb">
- <h2>Dependencies and Prerequisites</h2>
-
- <ul>
- <li>Android 2.2 (API level 8) or higher</li>
- <li><a href="{@docRoot}tools/testing-support-library/index.html">
- Android Testing Support Library</a></li>
- <li><a href="{@docRoot}tools/studio/index.html">Android Studio (latest version)</a>.</li>
- </ul>
-
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#setup">Set Up Your Testing Environment</a></li>
- <li><a href="#build">Create a Instrumented Unit Test Class</a></li>
- <li><a href="#run">Run Instrumented Unit Tests</a></li>
+ <li><a href="#build">Create a Instrumented Unit Test Class</a>
+ <ol>
+ <li><a href="#test-suites">Create a test suite</a></li>
+ </ol>
+ </li>
+ <li><a href="#run">Run Instrumented Unit Tests</a>
+ <ol>
+ <li><a href="#run-ctl">Run your tests with Firebase Test Lab</a></li>
+ </ol>
+ </li>
</ol>
<h2>Try it out</h2>
@@ -36,25 +35,88 @@
</div>
</div>
-<p>
-Instrumented unit tests are unit tests that run on physical devices and emulators, instead of
-the Java Virtual Machine (JVM) on your local machine. You should create instrumented unit tests
-if your tests need access to instrumentation information (such as the target app's
-{@link android.content.Context}) or if they require the real implementation of an Android framework
-component (such as a {@link android.os.Parcelable} or {@link android.content.SharedPreferences}
-object). Using instrumented unit tests also helps to reduce the effort required to write and
-maintain mock code. You are still free to use a mocking framework, if you choose, to simulate any
-dependency relationships. Instrumented unit tests can take advantage of the Android framework APIs
-and supporting APIs, such as the Android Testing Support Library.
-</p>
+<p>Instrumented unit tests are tests that run on physical devices and
+emulators, and they can take advantage of the Android framework APIs and
+supporting APIs, such as the Android Testing Support Library. You should create
+instrumented unit tests if your tests need access to instrumentation
+information (such as the target app's {@link android.content.Context}) or if
+they require the real implementation of an Android framework component (such as
+a {@link android.os.Parcelable} or {@link android.content.SharedPreferences}
+object).</p>
+
+<p>Using instrumented unit tests also helps to reduce the effort required to
+write and maintain mock code. You are still free to use a mocking framework, if
+you choose, to simulate any dependency relationships.</p>
+
<h2 id="setup">Set Up Your Testing Environment</h2>
-<p>Before building your instrumented unit test, make sure to configure your test source code
-location and project dependencies, as described in
-<a href="{@docRoot}training/testing/start/index.html#config-instrumented-tests">
-Getting Started with Testing</a>.</p>
+
+<p>In your Android Studio project, you must store the source files for
+instrumented tests at
+<code><var>module-name</var>/src/androidTests/java/</code>. This directory
+already exists when you create a new project.</p>
+
+<p>Before you begin, you should
+ <a href="{@docRoot}tools/testing-support-library/index.html#setup">download
+ the Android Testing Support Library Setup</a>, which provides APIs that allow
+ you to quickly build and run instrumented test code for your apps. The
+ Testing Support Library includes a JUnit 4 test runner (<a href=
+ "{@docRoot}tools/testing-support-library/index.html#AndroidJUnitRunner">AndroidJUnitRunner</a>
+ ) and APIs for functional UI tests (<a href=
+ "{@docRoot}tools/testing-support-library/index.html#Espresso">Espresso</a>
+ and <a href=
+ "{@docRoot}tools/testing-support-library/index.html#UIAutomator">UI
+ Automator</a>).
+</p>
+
+<p>You also need to configure the Android testing dependencies for your project
+to use the test runner and the rules APIs provided by the Testing Support
+Library. To simplify your test development, you should also include the
+<a href="https://github.com/hamcrest" class="external-link">Hamcrest</a>
+library, which lets you create more flexible assertions using the Hamcrest
+matcher APIs.</p>
+
+<p>
+ In your app's top-level {@code build.gradle} file, you need to specify these
+ libraries as dependencies:
+</p>
+
+<pre>
+dependencies {
+ androidTestCompile 'com.android.support:support-annotations:24.0.0'
+ androidTestCompile 'com.android.support.test:runner:0.5'
+ androidTestCompile 'com.android.support.test:rules:0.5'
+ // Optional -- Hamcrest library
+ androidTestCompile 'org.hamcrest:hamcrest-library:1.3'
+ // Optional -- UI testing with Espresso
+ androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
+ // Optional -- UI testing with UI Automator
+ androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
+}
+</pre>
+
+
+<p>
+ To use JUnit 4 test classes, make sure to specify <a href=
+ "{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code
+ AndroidJUnitRunner}</a> as the default test instrumentation runner in your
+ project by including the following setting in your app's module-level {@code build.gradle}
+ file:
+</p>
+
+<pre>
+android {
+ defaultConfig {
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ }
+}
+</pre>
+
+
+
<h2 id="build">Create an Instrumented Unit Test Class</h2>
+
<p>
Your instrumented unit test class should be written as a JUnit 4 test class. To learn more about
creating JUnit 4 test classes and using JUnit 4 assertions and annotations, see
@@ -119,7 +181,7 @@
}
</pre>
-<h3 id="test-suites">Creating a test suite</h3>
+<h3 id="test-suites">Create a test suite</h3>
<p>
To organize the execution of your instrumented unit tests, you can group a collection of test
classes in a <em>test suite</em> class and run these tests together. Test suites can be nested;
@@ -162,9 +224,198 @@
public class UnitTestSuite {}
</pre>
+
<h2 id="run">Run Instrumented Unit Tests</h2>
+
+<p>To run your instrumented tests, follow these steps:</p>
+
+<ol>
+ <li>Be sure your project is synchronized with Gradle by clicking
+ <b>Sync Project</b> <img src="/images/tools/sync-project.png" alt=""
+ class="inline-icon"> in the toolbar.</li>
+
+ <li>Run your test in one of the following ways:
+ <ul>
+ <li>To run a single test, open the <b>Project</b> window, and then
+ right-click a test and click <strong>Run</strong> <img src=
+ "{@docRoot}images/tools/as-run.png" alt="" class="inline-icon">.</li>
+ <li>To test all methods in a class, right-click a class or method in the
+test file and click <b>Run</b> <img src=
+ "{@docRoot}images/tools/as-run.png" alt="" class="inline-icon">.
+ <li>To run all tests in a directory, right-click on the
+ directory and select <strong>Run tests</strong> <img src=
+ "{@docRoot}images/tools/as-run.png" alt="" class="inline-icon">.
+ </li>
+ </ul>
+ </li>
+
+</ol>
+
<p>
-To run your test, follow the steps for running instrumented tests
-described in <a href="{@docRoot}training/testing/start/index.html#run-instrumented-tests">
-Getting Started with Testing</a>.
+ The <a href="{@docRoot}tools/building/plugin-for-gradle.html">Android Plugin
+ for Gradle</a> compiles the instrumented test code located in the default
+ directory ({@code src/androidTest/java/}), builds a test APK and production
+ APK, installs both APKs on the connected device or emulator, and runs the
+ tests. Android Studio then displays the results of the instrumented test execution in the
+ <em>Run</em> window.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> While running or debugging instrumented tests,
+ Android Studio does not inject the additional methods required for <a href=
+ "{@docRoot}tools/building/building-studio.html#instant-run">Instant Run</a>
+ and turns the feature off.
+</p>
+
+
+<h3 id="run-ctl">Run your tests with Firebase Test Lab</h3>
+
+<p>Using <a href="https://firebase.google.com/docs/test-lab/">Firebase Test
+Lab</a>, you can simultaneously test your app on many popular Android devices
+and configurations such as locale, orientation, screen size, and platform
+version. These tests run on actual physical devices in remote Google data
+centers. You can deploy to Firebase Test Lab directly from Android Studio or
+from the command line. Test results provide test logs and include the details
+of any app failures.</p>
+
+<p>
+ Before you can start using Firebase Test Lab, you need to:
+</p>
+
+<ol>
+ <li>
+ <a href="https://console.developers.google.com/freetrial">Create a
+ Google Cloud Platform account</a> to use with active billing.
+ </li>
+
+ <li>
+ <a href="https://support.google.com/cloud/answer/6251787">Create a Google
+ Cloud project</a> for your app.
+ </li>
+
+ <li>
+ <a href="https://support.google.com/cloud/answer/6288653">Set up an active
+ billing account</a> and associate it with the project you just created.
+ </li>
+</ol>
+
+
+<h4 id="configure-matrix">
+Configure a test matrix and run a test
+</h4>
+
+<p>
+ Android Studio provides integrated tools that allow you to configure how you
+ want to deploy your tests to Firebase Test Lab. After you have created a Google
+ Cloud project with active billing, you can create a test configuration and
+ run your tests:
+</p>
+
+<ol>
+ <li>Click <strong>Run</strong> > <strong>Edit Configurations</strong> from
+ the main menu.
+ </li>
+
+ <li>Click <strong>Add New Configuration (+)</strong> and select
+ <strong>Android Tests</strong>.
+ </li>
+
+ <li>In the Android Test configuration dialog:
+ <ol type="a">
+ <li>Enter or select the details of your test, such as the test name, module
+ type, test type, and test class.
+ </li>
+
+ <li>From the <em>Target</em> drop-down menu under <em>Deployment Target
+ Options</em>, select <strong>Cloud Test Lab Device Matrix</strong>.
+ </li>
+
+ <li>If you are not logged in, click <strong>Connect to Google Cloud
+ Platform</strong> and allow Android Studio access to your account.
+ </li>
+
+ <li>Next to <em>Cloud Project</em>, click the <img src=
+ "{@docRoot}images/tools/as-wrench.png" alt="wrench and nut" style=
+ "vertical-align:bottom;margin:0;"> button and select your Google Cloud
+ Platform project from the list.
+ </li>
+ </ol>
+ </li>
+
+ <li>Create and configure a test matrix:
+ <ol type="a">
+ <li>Next to the <em>Matrix Configuration</em> drop-down list, click <strong>
+ Open Dialog</strong> <img src="{@docRoot}images/tools/as-launchavdm.png"
+ alt="ellipses button" style="vertical-align:bottom;margin:0;">.
+ </li>
+
+ <li>Click <strong>Add New Configuration (+)</strong>.
+ </li>
+
+ <li>In the <strong>Name</strong> field, enter a name for your new
+ configuration.
+ </li>
+
+ <li>Select the device(s), Android version(s), locale(s) and screen
+ orientation(s) that you want to test your app with. Firebase Test Lab will
+ test your app against every combination of your selections when generating
+ test results.
+ </li>
+
+ <li>Click <strong>OK</strong> to save your configuration.
+ </li>
+ </ol>
+ </li>
+
+ <li>Click <strong>OK</strong> in the <em>Run/Debug Configurations</em> dialog
+ to exit.
+ </li>
+
+ <li>Run your tests by clicking <strong>Run</strong> <img src=
+ "{@docRoot}images/tools/as-run.png" alt="" style=
+ "vertical-align:bottom;margin:0;">.
+ </li>
+</ol>
+
+<img src="{@docRoot}images/training/ctl-config.png" alt="">
+<p class="img-caption">
+ <strong>Figure 1.</strong> Creating a test configuration for Firebase Test
+ Lab.
+</p>
+
+<h4 id="ctl-results">
+ Analyzing test results
+</h4>
+
+<p>
+ When Firebase Test Lab completes running your tests, the <em>Run</em> window
+ will open to show the results, as shown in figure 2. You may need to click
+ <strong>Show Passed</strong> <img src="{@docRoot}images/tools/as-ok.png" alt=
+ "" style="vertical-align:bottom;margin:0;"> to see all your executed tests.
+</p>
+
+<img src="{@docRoot}images/training/ctl-test-results.png" alt="">
+
+<p class="img-caption">
+ <strong>Figure 2.</strong> Viewing the results of instrumented tests using
+ Firebase Test Lab.
+</p>
+
+<p>
+ You can also analyze your tests on the web by following the link displayed at
+ the beginning of the test execution log in the <em>Run</em> window, as shown
+ in figure 3.
+</p>
+
+<img src="{@docRoot}images/training/ctl-exec-log.png" alt="">
+
+<p class="img-caption">
+ <strong>Figure 3.</strong> Click the link to view detailed test results on
+ the web.
+</p>
+
+<p>
+ To learn more about interpreting web results, see <a href=
+ "https://firebase.google.com/docs/test-lab/analyzing-results">Analyze
+ Firebase Test Lab for Android Results</a>.
</p>
\ No newline at end of file
diff --git a/docs/html/training/testing/unit-testing/local-unit-tests.jd b/docs/html/training/testing/unit-testing/local-unit-tests.jd
index 893d957..25b62fa 100644
--- a/docs/html/training/testing/unit-testing/local-unit-tests.jd
+++ b/docs/html/training/testing/unit-testing/local-unit-tests.jd
@@ -7,17 +7,16 @@
<!-- This is the training bar -->
<div id="tb-wrapper">
<div id="tb">
- <h2>Dependencies and Prerequisites</h2>
-
- <ul>
- <li><a href="{@docRoot}tools/studio/index.html">Android Studio (latest version)</a>.</li>
- </ul>
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#setup">Set Up Your Testing Environment</a></li>
- <li><a href="#build">Create a Local Unit Test Class</a></li>
+ <li><a href="#build">Create a Local Unit Test Class</a>
+ <ol>
+ <li><a href="#mocking-dependencies">Mock Android dependencies</a></li>
+ </ol>
+ </li>
<li><a href="#run">Run Local Unit Tests</a></li>
</ol>
@@ -42,13 +41,35 @@
dependency relationships.</p>
<h2 id="setup">Set Up Your Testing Environment</h2>
-<p>Before building your local unit test, make sure to configure your test source code location and
-project dependencies, as described in
-<a href="{@docRoot}training/testing/start/index.html#config-local-tests">
-Getting Started with Testing</a>.</p>
+
+<p>In your Android Studio project, you must store the source files for local
+unit tests at <code><var>module-name</var>/src/test/java/</code>. This directory
+already exists when you create a new project.</p>
+
+<p>You also need to configure the testing dependencies for your project to use
+the standard APIs provided by the JUnit 4 framework. If your test needs to
+interact with Android dependencies, include the <a href=
+"https://github.com/mockito/mockito" class="external-link">Mockito</a> library
+to simplify your local unit tests. To learn more about using mock objects in
+your local unit tests, see <a href=
+"{@docRoot}training/testing/unit-testing/local-unit-tests.html#mocking-dependencies">
+Mocking Android dependencies</a>.</p>
+
+<p>In your app's top-level {@code build.gradle} file, you need to specify these
+libraries as dependencies:</p>
+
+<pre>
+dependencies {
+ // Required -- JUnit 4 framework
+ testCompile 'junit:junit:4.12'
+ // Optional -- Mockito framework
+ testCompile 'org.mockito:mockito-core:1.10.19'
+}
+</pre>
<h2 id="build">Create a Local Unit Test Class</h2>
+
<p>Your local unit test class should be written as a JUnit 4 test class.
<a href="http://junit.org/" class="external-link">JUnit</a> is the most popular
and widely-used unit testing framework for Java. The latest version of this framework, JUnit 4,
@@ -90,7 +111,7 @@
Hamcrest matchers</a> (such as the {@code is()} and {@code equalTo()} methods) to match the
returned result against the expected result.</p>
-<h3 id="mocking-dependencies">Mocking Android dependencies</h3>
+<h3 id="mocking-dependencies">Mock Android dependencies</h3>
<p>
By default, the <a href="{@docRoot}tools/building/plugin-for-gradle.html">
Android Plug-in for Gradle</a> executes your local unit tests against a modified
@@ -174,10 +195,37 @@
class="external-link">sample code</a>.
</p>
-<h2 id="run">Run Local Unit Tests</h2>
-<p>
-To run your tests, follow the steps for running local unit tests
-described in <a href="{@docRoot}training/testing/start/index.html#run-local-tests">
-Getting Started with Testing</a>.
-</p>
+<h2 id="run">Run Local Unit Tests</h2>
+
+<p>To run your local unit tests, follow these steps:</p>
+
+<ol>
+
+ <li>Be sure your project is synchronized with Gradle by clicking
+ <b>Sync Project</b> <img src="/images/tools/sync-project.png" alt=""
+ class="inline-icon"> in the toolbar.</li>
+
+ <li>Run your test in one of the following ways:
+ <ul>
+ <li>To run a single test, open the <b>Project</b> window, and then
+ right-click a test and click <strong>Run</strong> <img src=
+ "{@docRoot}images/tools/as-run.png" alt="" class="inline-icon">.</li>
+ <li>To test all methods in a class, right-click a class or method in the
+test file and click <b>Run</b> <img src=
+ "{@docRoot}images/tools/as-run.png" alt="" class="inline-icon">.
+ <li>To run all tests in a directory, right-click on the
+ directory and select <strong>Run tests</strong> <img src=
+ "{@docRoot}images/tools/as-run.png" alt="" class="inline-icon">.
+ </li>
+ </ul>
+ </li>
+
+</ol>
+
+<p>
+ The Android Plugin for Gradle compiles the local unit test code located in
+ the default directory ({@code src/test/java/}), builds a test app, and
+ executes it locally using the default test runner class. Android Studio then
+ displays the results in the <b>Run</b> window.
+</p>
diff --git a/docs/html/wear/preview/api-overview.jd b/docs/html/wear/preview/api-overview.jd
index 543313a..11331a7 100644
--- a/docs/html/wear/preview/api-overview.jd
+++ b/docs/html/wear/preview/api-overview.jd
@@ -4,9 +4,6 @@
page.image=images/cards/card-n-apis_2x.png
@jd:body
-
-
-
<div id="qv-wrapper">
<div id="qv">
<h2>Key developer features</h2>
@@ -298,36 +295,35 @@
authentication capabilities will be more powerful; apps will have new ways to
authenticate.</p>
- <h4> Authentication tokens can be passed over the Wearable Data Layer </h4>
-
-<p>For Android-paired watches (only), the phone will securely transfer authentication
- data to a watch app via the
- <a href="{@docRoot}training/wearables/data-layer/index.html">
- Wearable Data Layer API</a>. The data can be transferred as
- Messages or Data Items. </p>
-
-<p>If your watch app needs to determine if your phone app is installed, you can
-advertise a capability on the phone app and retrieve the capability on the watch.
- For more information, see following sections of
- <a href="{@docRoot}training/wearables/data-layer/messages.html">
- Sending and Receiving Messages</a>:
- <ul>
- <li>Advertise Capabilities</li>
- <li>Retrieve the Nodes with the Required Capabilities</li>
- </ul>
<h4>Users can enter a username and password on a watch</h4>
-<p>Google Keyboard will be standard on Android Wear, allowing for direct text entry.
- This feature will work as expected with standard
- <a href="{@docRoot}reference/android/widget/EditText.html">
- EditText widgets</a>. For passwords, the {@code textPassword} attribute will be
- used.
+<p>Google Keyboard will be standard on Android Wear, allowing for direct text
+entry. This feature will work as expected with standard
+<a href="{@docRoot}reference/android/widget/EditText.html">EditText widgets</a>.
+For passwords, the {@code textPassword} attribute will be used.</p>
<h4>Utilizing Account Manager</h4>
-Android Wear will include the <a href="{@docRoot}reference/android/accounts/AccountManager.html">
+
+<p>Android Wear will include the
+<a href="{@docRoot}reference/android/accounts/AccountManager.html">
AccountManager</a>, which will be accessible for syncing and storing account
- data, as it is on an Android phone.
-</p>
+data, as it is on an Android phone.</p>
+<h4>Authentication tokens can be passed over the Wearable Data Layer</h4>
+<p>For Android-paired watches (only), a phone securely
+transfers authentication credentials to a watch app via the
+<a href="{@docRoot}training/wearables/data-layer/index.html">
+Wearable Data Layer API</a>. The credentials can be transferred as
+messages or data items.</p>
+<p>If your watch app needs to determine if your phone app is installed, you can
+advertise a capability on the phone app and retrieve the capability on the
+watch. For more information, see the following sections of
+<a href="{@docRoot}training/wearables/data-layer/messages.html">
+Sending and Receiving Messages</a>:</p>
+
+<ul>
+ <li>Advertise Capabilities</li>
+ <li>Retrieve the Nodes with the Required Capabilities</li>
+</ul>
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 6bb93aec..0bdc76f 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -239,6 +239,17 @@
@Override
public void draw(Canvas canvas) {
+ if (!canvas.isHardwareAccelerated() && mAnimatorSet instanceof VectorDrawableAnimatorRT) {
+ // If we have SW canvas and the RT animation is waiting to start, We need to fallback
+ // to UI thread animation for AVD.
+ if (!mAnimatorSet.isRunning() &&
+ ((VectorDrawableAnimatorRT) mAnimatorSet).mPendingAnimationActions.size() > 0) {
+ VectorDrawableAnimatorRT oldAnim = (VectorDrawableAnimatorRT) mAnimatorSet;
+ mAnimatorSet = new VectorDrawableAnimatorUI(this);
+ mAnimatorSet.init(mAnimatorSetFromXml);
+ oldAnim.transferPendingActions(mAnimatorSet);
+ }
+ }
mAnimatorSet.onDraw(canvas);
mAnimatedVectorState.mVectorDrawable.draw(canvas);
}
@@ -1590,6 +1601,25 @@
private static void callOnFinished(VectorDrawableAnimatorRT set, int id) {
set.onAnimationEnd(id);
}
+
+ private void transferPendingActions(VectorDrawableAnimator animatorSet) {
+ for (int i = 0; i < mPendingAnimationActions.size(); i++) {
+ int pendingAction = mPendingAnimationActions.get(i);
+ if (pendingAction == START_ANIMATION) {
+ animatorSet.start();
+ } else if (pendingAction == END_ANIMATION) {
+ animatorSet.end();
+ } else if (pendingAction == REVERSE_ANIMATION) {
+ animatorSet.reverse();
+ } else if (pendingAction == RESET_ANIMATION) {
+ animatorSet.reset();
+ } else {
+ throw new UnsupportedOperationException("Animation action " +
+ pendingAction + "is not supported");
+ }
+ }
+ mPendingAnimationActions.clear();
+ }
}
private static native long nCreateAnimatorSet();
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index c6977746..d5143da 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -75,6 +75,9 @@
private long mEnterAnimationEnd;
private long mExitAnimationEnd;
+ /** Callback that blocks invalidation. Used for drawable initialization. */
+ private BlockInvalidateCallback mBlockInvalidateCallback;
+
// overrides from Drawable
@Override
@@ -500,11 +503,14 @@
* @param d The drawable to initialize.
*/
private void initializeDrawableForDisplay(Drawable d) {
+ if (mBlockInvalidateCallback == null) {
+ mBlockInvalidateCallback = new BlockInvalidateCallback();
+ }
+
// Temporary fix for suspending callbacks during initialization. We
// don't want any of these setters causing an invalidate() since that
// may call back into DrawableContainer.
- final Callback cb = d.getCallback();
- d.setCallback(null);
+ d.setCallback(mBlockInvalidateCallback.wrap(d.getCallback()));
try {
if (mDrawableContainerState.mEnterFadeDuration <= 0 && mHasAlpha) {
@@ -537,7 +543,7 @@
hotspotBounds.right, hotspotBounds.bottom);
}
} finally {
- d.setCallback(cb);
+ d.setCallback(mBlockInvalidateCallback.unwrap());
}
}
@@ -1215,4 +1221,41 @@
mLastIndex = -1;
mLastDrawable = null;
}
+
+ /**
+ * Callback that blocks drawable invalidation.
+ */
+ private static class BlockInvalidateCallback implements Drawable.Callback {
+ private Drawable.Callback mCallback;
+
+ public BlockInvalidateCallback wrap(Drawable.Callback callback) {
+ mCallback = callback;
+ return this;
+ }
+
+ public Drawable.Callback unwrap() {
+ final Drawable.Callback callback = mCallback;
+ mCallback = null;
+ return callback;
+ }
+
+ @Override
+ public void invalidateDrawable(@NonNull Drawable who) {
+ // Ignore invalidation.
+ }
+
+ @Override
+ public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
+ if (mCallback != null) {
+ mCallback.scheduleDrawable(who, what, when);
+ }
+ }
+
+ @Override
+ public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) {
+ if (mCallback != null) {
+ mCallback.unscheduleDrawable(who, what);
+ }
+ }
+ }
}
diff --git a/libs/hwui/AnimationContext.cpp b/libs/hwui/AnimationContext.cpp
index 097be08..5759ccd 100644
--- a/libs/hwui/AnimationContext.cpp
+++ b/libs/hwui/AnimationContext.cpp
@@ -63,7 +63,7 @@
mCurrentFrameAnimations.mNextHandle = head;
head->mPreviousHandle = &mCurrentFrameAnimations;
}
- mFrameTimeMs = mClock.computeFrameTimeMs();
+ mFrameTimeMs = ns2ms(mClock.latestVsync());
}
void AnimationContext::runRemainingAnimations(TreeInfo& info) {
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index b8a5ce6..37d9d0e7 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -946,6 +946,7 @@
Rect dstRect(op.unmappedBounds);
boundsTransform.mapRect(dstRect);
+ dstRect.roundOut();
dstRect.doIntersect(mCanvasState.currentSnapshot()->getRenderTargetClip());
if (dstRect.isEmpty()) {
diff --git a/libs/hwui/PropertyValuesAnimatorSet.cpp b/libs/hwui/PropertyValuesAnimatorSet.cpp
index e416e0c..796c73b 100644
--- a/libs/hwui/PropertyValuesAnimatorSet.cpp
+++ b/libs/hwui/PropertyValuesAnimatorSet.cpp
@@ -29,7 +29,6 @@
PropertyAnimator* animator = new PropertyAnimator(propertyValuesHolder,
interpolator, startDelay, duration, repeatCount);
mAnimators.emplace_back(animator);
- setListener(new PropertyAnimatorSetListener(this));
// Check whether any child animator is infinite after adding it them to the set.
if (repeatCount == -1) {
@@ -42,6 +41,7 @@
setStartValue(0);
mLastFraction = 0.0f;
setInterpolator(new LinearInterpolator());
+ setListener(new PropertyAnimatorSetListener(this));
}
void PropertyValuesAnimatorSet::onFinished(BaseRenderNodeAnimator* animator) {
@@ -115,7 +115,7 @@
std::sort(mAnimators.begin(), mAnimators.end(), [](auto& a, auto&b) {
return a->getTotalDuration() < b->getTotalDuration();
});
- mDuration = mAnimators[mAnimators.size() - 1]->getTotalDuration();
+ mDuration = mAnimators.empty() ? 0 : mAnimators[mAnimators.size() - 1]->getTotalDuration();
mInitialized = true;
}
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 5a3300a..f8797bf 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -474,7 +474,7 @@
}
#endif
-void RenderNode::syncDisplayList(TreeObserver* observer) {
+void RenderNode::syncDisplayList(TreeInfo* info) {
// Make sure we inc first so that we don't fluctuate between 0 and 1,
// which would thrash the layer cache
if (mStagingDisplayList) {
@@ -482,7 +482,7 @@
child->renderNode->incParentRefCount();
}
}
- deleteDisplayList(observer);
+ deleteDisplayList(info ? info->observer : nullptr, info);
mDisplayList = mStagingDisplayList;
mStagingDisplayList = nullptr;
if (mDisplayList) {
@@ -501,15 +501,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(info.observer);
+ syncDisplayList(&info);
damageSelf(info);
}
}
-void RenderNode::deleteDisplayList(TreeObserver* observer) {
+void RenderNode::deleteDisplayList(TreeObserver* observer, TreeInfo* info) {
if (mDisplayList) {
for (auto&& child : mDisplayList->getChildren()) {
- child->renderNode->decParentRefCount(observer);
+ child->renderNode->decParentRefCount(observer, info);
}
}
delete mDisplayList;
@@ -541,35 +541,38 @@
}
}
-void RenderNode::destroyHardwareResources(TreeObserver* observer) {
+void RenderNode::destroyHardwareResources(TreeObserver* observer, TreeInfo* info) {
if (mLayer) {
destroyLayer(mLayer);
mLayer = nullptr;
}
if (mDisplayList) {
for (auto&& child : mDisplayList->getChildren()) {
- child->renderNode->destroyHardwareResources(observer);
+ child->renderNode->destroyHardwareResources(observer, info);
}
if (mNeedsDisplayListSync) {
// Next prepare tree we are going to push a new display list, so we can
// drop our current one now
- deleteDisplayList(observer);
+ deleteDisplayList(observer, info);
}
}
}
-void RenderNode::decParentRefCount(TreeObserver* observer) {
+void RenderNode::decParentRefCount(TreeObserver* observer, TreeInfo* info) {
LOG_ALWAYS_FATAL_IF(!mParentCount, "already 0!");
mParentCount--;
if (!mParentCount) {
if (observer) {
observer->onMaybeRemovedFromTree(this);
}
+ if (CC_UNLIKELY(mPositionListener.get())) {
+ mPositionListener->onPositionLost(*this, info);
+ }
// 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(observer);
+ destroyHardwareResources(observer, info);
}
}
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index acdc3d8..f80be5e 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -196,7 +196,7 @@
}
ANDROID_API virtual void prepareTree(TreeInfo& info);
- void destroyHardwareResources(TreeObserver* observer);
+ void destroyHardwareResources(TreeObserver* observer, TreeInfo* info = nullptr);
// UI thread only!
ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
@@ -228,10 +228,19 @@
OffscreenBuffer** getLayerHandle() { return &mLayer; } // ugh...
#endif
+ // Note: The position callbacks are relying on the listener using
+ // the frameNumber to appropriately batch/synchronize these transactions.
+ // There is no other filtering/batching to ensure that only the "final"
+ // state called once per frame.
class ANDROID_API PositionListener {
public:
virtual ~PositionListener() {}
+ // Called when the RenderNode's position changes
virtual void onPositionUpdated(RenderNode& node, const TreeInfo& info) = 0;
+ // Called when the RenderNode no longer has a position. As in, it's
+ // no longer being drawn.
+ // Note, tree info might be null
+ virtual void onPositionLost(RenderNode& node, const TreeInfo* info) = 0;
};
// Note this is not thread safe, this needs to be called
@@ -306,7 +315,7 @@
void syncProperties();
- void syncDisplayList(TreeObserver* observer);
+ void syncDisplayList(TreeInfo* info);
void prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer);
void pushStagingPropertiesChanges(TreeInfo& info);
@@ -317,11 +326,11 @@
#endif
void prepareLayer(TreeInfo& info, uint32_t dirtyMask);
void pushLayerUpdate(TreeInfo& info);
- void deleteDisplayList(TreeObserver* observer);
+ void deleteDisplayList(TreeObserver* observer, TreeInfo* info = nullptr);
void damageSelf(TreeInfo& info);
void incParentRefCount() { mParentCount++; }
- void decParentRefCount(TreeObserver* observer);
+ void decParentRefCount(TreeObserver* observer, TreeInfo* info = nullptr);
String8 mName;
sp<VirtualLightRefBase> mUserContext;
diff --git a/libs/hwui/renderthread/TimeLord.cpp b/libs/hwui/renderthread/TimeLord.cpp
index f846d6a..6c2575f 100644
--- a/libs/hwui/renderthread/TimeLord.cpp
+++ b/libs/hwui/renderthread/TimeLord.cpp
@@ -43,10 +43,6 @@
return mFrameTimeNanos;
}
-nsecs_t TimeLord::computeFrameTimeMs() {
- return nanoseconds_to_milliseconds(computeFrameTimeNanos());
-}
-
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/renderthread/TimeLord.h b/libs/hwui/renderthread/TimeLord.h
index 5464399..68a0f7f 100644
--- a/libs/hwui/renderthread/TimeLord.h
+++ b/libs/hwui/renderthread/TimeLord.h
@@ -34,7 +34,6 @@
// returns true if the vsync is newer, false if it was rejected for staleness
bool vsyncReceived(nsecs_t vsync);
nsecs_t latestVsync() { return mFrameTimeNanos; }
- nsecs_t computeFrameTimeMs();
nsecs_t computeFrameTimeNanos();
private:
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index af1fbd8..af54e07 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -1007,6 +1007,40 @@
EXPECT_EQ(4, renderer.getIndex());
}
+RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_round) {
+ class SaveLayerUnclippedRoundTestRenderer : public TestRendererBase {
+ public:
+ void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(0, mIndex++);
+ EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds)
+ << "Bounds rect should round out";
+ }
+ void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {}
+ void onRectOp(const RectOp& op, const BakedOpState& state) override {}
+ void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(1, mIndex++);
+ EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds)
+ << "Bounds rect should round out";
+ }
+ };
+
+ auto node = TestUtils::createNode(0, 0, 200, 200,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.saveLayerAlpha(10.95f, 10.5f, 189.75f, 189.25f, // values should all round out
+ 128, (SaveFlags::Flags)(0));
+ canvas.drawRect(0, 0, 200, 200, SkPaint());
+ canvas.restore();
+ });
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
+
+ SaveLayerUnclippedRoundTestRenderer renderer;
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+ EXPECT_EQ(2, renderer.getIndex());
+}
+
RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
class SaveLayerUnclippedMergedClearsTestRenderer : public TestRendererBase {
public:
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index b246360..2b3ed87 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -2008,7 +2008,7 @@
* No-op method to keep backward-compatibility.
* Don't use it. Use {@link #registerGnssMeasurementsCallback} instead.
* @hide
- * @deprecated
+ * @deprecated Not supported anymore.
*/
@Deprecated
@SystemApi
@@ -2065,7 +2065,7 @@
* No-op method to keep backward-compatibility.
* Don't use it. Use {@link #registerGnssNavigationMessageCallback} instead.
* @hide
- * @deprecated
+ * @deprecated Not supported anymore.
*/
@Deprecated
@SystemApi
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 8efd599..39184f1 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -467,11 +467,11 @@
* <p>
* If the audio source is not set with {@link #setAudioSource(int)},
* {@link MediaRecorder.AudioSource#DEFAULT} is used.
- * <br>If the audio format is not specified or is incomplete, its sample rate will be the
- * default output sample rate of the device (see
- * {@link AudioManager#PROPERTY_OUTPUT_SAMPLE_RATE}), its channel configuration will be
+ * <br>If the audio format is not specified or is incomplete, its channel configuration will be
* {@link AudioFormat#CHANNEL_IN_MONO}, and the encoding will be
* {@link AudioFormat#ENCODING_PCM_16BIT}.
+ * The sample rate will depend on the device actually selected for capture and can be queried
+ * with {@link #getSampleRate()} method.
* <br>If the buffer size is not specified with {@link #setBufferSizeInBytes(int)},
* the minimum buffer size for the source is used.
*/
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 9a81668..12d5ead 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -619,11 +619,11 @@
* <p>
* If the audio attributes are not set with {@link #setAudioAttributes(AudioAttributes)},
* attributes comprising {@link AudioAttributes#USAGE_MEDIA} will be used.
- * <br>If the audio format is not specified or is incomplete, its sample rate will be the
- * default output sample rate of the device (see
- * {@link AudioManager#PROPERTY_OUTPUT_SAMPLE_RATE}), its channel configuration will be
+ * <br>If the audio format is not specified or is incomplete, its channel configuration will be
* {@link AudioFormat#CHANNEL_OUT_STEREO} and the encoding will be
* {@link AudioFormat#ENCODING_PCM_16BIT}.
+ * The sample rate will depend on the device actually selected for playback and can be queried
+ * with {@link #getSampleRate()} method.
* <br>If the buffer size is not specified with {@link #setBufferSizeInBytes(int)},
* and the mode is {@link AudioTrack#MODE_STREAM}, the minimum buffer size is used.
* <br>If the transfer mode is not specified with {@link #setTransferMode(int)},
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 45d0cc0..07d1f75 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -1372,16 +1372,33 @@
* May return {@code null}, if the codec did not publish any measurement
* data.
* <p>
- * This is a performance estimate provided by the device manufacturer
- * based on full-speed decoding and encoding measurements in various configurations
+ * This is a performance estimate provided by the device manufacturer based on statistical
+ * sampling of full-speed decoding and encoding measurements in various configurations
* of common video sizes supported by the codec. As such it should only be used to
* compare individual codecs on the device. The value is not suitable for comparing
* different devices or even different android releases for the same device.
* <p>
- * The returned range corresponds to the fastest frame rates achieved in the tested
- * configurations. It is interpolated from the nearest frame size(s) tested. Codec
- * performance is severely impacted by other activity on the device, and can vary
- * significantly.
+ * <em>On {@link android.os.Build.VERSION_CODES#M} release</em> the returned range
+ * corresponds to the fastest frame rates achieved in the tested configurations. As
+ * such, it should not be used to gauge guaranteed or even average codec performance
+ * on the device.
+ * <p>
+ * <em>On {@link android.os.Build.VERSION_CODES#N} release</em> the returned range
+ * corresponds closer to sustained performance <em>in tested configurations</em>.
+ * One can expect to achieve sustained performance higher than the lower limit more than
+ * 50% of the time, and higher than half of the lower limit at least 90% of the time
+ * <em>in tested configurations</em>.
+ * Conversely, one can expect performance lower than twice the upper limit at least
+ * 90% of the time.
+ * <p class=note>
+ * Tested configurations use a single active codec. For use cases where multiple
+ * codecs are active, applications can expect lower and in most cases significantly lower
+ * performance.
+ * <p class=note>
+ * The returned range value is interpolated from the nearest frame size(s) tested.
+ * Codec performance is severely impacted by other activity on the device as well
+ * as environmental factors (such as battery level, temperature or power source), and can
+ * vary significantly even in a steady environment.
* <p class=note>
* Use this method in cases where only codec performance matters, e.g. to evaluate if
* a codec has any chance of meeting a performance target. Codecs are listed
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 4d40e6b..8d4a151 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -476,10 +476,10 @@
* <td>This method can be called in any state and calling it does not change
* the object state. </p></td></tr>
* <tr><td>setPlaybackParams</p></td>
- * <td>any </p></td>
- * <td>{} </p></td>
- * <td>This method can be called in any state and calling it does not change
- * the object state. </p></td></tr>
+ * <td>{Initialized, Prepared, Started, Paused, PlaybackCompleted, Error}</p></td>
+ * <td>{Idle, Stopped} </p></td>
+ * <td>This method will change state in some cases, depending on when it's called.
+ * </p></td></tr>
* <tr><td>setScreenOnWhilePlaying</></td>
* <td>any </p></td>
* <td>{} </p></td>
@@ -1449,12 +1449,18 @@
}
/**
- * Sets playback rate using {@link PlaybackParams}.
+ * Sets playback rate using {@link PlaybackParams}. The object sets its internal
+ * PlaybackParams to the input, except that the object remembers previous speed
+ * when input speed is zero. This allows the object to resume at previous speed
+ * when start() is called. Calling it before the object is prepared does not change
+ * the object state. After the object is prepared, calling it with zero speed is
+ * equivalent to calling pause(). After the object is prepared, calling it with
+ * non-zero speed is equivalent to calling start().
*
* @param params the playback params.
*
* @throws IllegalStateException if the internal player engine has not been
- * initialized.
+ * initialized or has been released.
* @throws IllegalArgumentException if params is not supported.
*/
public native void setPlaybackParams(@NonNull PlaybackParams params);
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index 359ebad..c62d930 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -68,16 +68,19 @@
if (sizeToRead <= kMinSizeToRead) {
sizeToRead = kMinSizeToRead;
}
+
void* tempBuffer = malloc(sizeToRead);
- if (tempBuffer != NULL) {
- size_t bytesRead = mStream->read(tempBuffer, sizeToRead);
- if (bytesRead != sizeToRead) {
- free(tempBuffer);
- return piex::Error::kFail;
- }
- mStreamBuffer.write(tempBuffer, bytesRead);
- free(tempBuffer);
+ if (tempBuffer == NULL) {
+ return piex::Error::kFail;
}
+
+ size_t bytesRead = mStream->read(tempBuffer, sizeToRead);
+ if (bytesRead != sizeToRead) {
+ free(tempBuffer);
+ return piex::Error::kFail;
+ }
+ mStreamBuffer.write(tempBuffer, bytesRead);
+ free(tempBuffer);
}
// Read bytes.
@@ -126,8 +129,8 @@
size_t size = fread((void*)data, sizeof(std::uint8_t), length, mFile);
mPosition += size;
- // Handle errors.
- if (ferror(mFile)) {
+ // Handle errors and verify the size.
+ if (ferror(mFile) || size != length) {
ALOGV("GetData read failed: (offset: %zu, length: %zu)", offset, length);
return piex::Error::kFail;
}
diff --git a/packages/CtsShim/CtsShim.apk b/packages/CtsShim/CtsShim.apk
index 7a27a43..2728903 100644
--- a/packages/CtsShim/CtsShim.apk
+++ b/packages/CtsShim/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/CtsShimPriv.apk b/packages/CtsShim/CtsShimPriv.apk
index 63e8688..9a8e75c 100644
--- a/packages/CtsShim/CtsShimPriv.apk
+++ b/packages/CtsShim/CtsShimPriv.apk
Binary files differ
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 9d4b50c..1922773 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -215,9 +215,12 @@
includeState(state);
// Advanced roots are shown by default without menu option if forced by config or intent.
- state.showAdvanced = Shared.shouldShowDeviceRoot(this, intent);
+ boolean forceAdvanced = Shared.shouldShowDeviceRoot(this, intent);
+ boolean chosenAdvanced = LocalPreferences.getShowDeviceRoot(this, state.action);
+ state.showAdvanced = forceAdvanced || chosenAdvanced;
+
// Menu option is shown for whitelisted intents if advanced roots are not shown by default.
- state.showAdvancedOption = !state.showAdvanced && (
+ state.showAdvancedOption = !forceAdvanced && (
Shared.shouldShowFancyFeatures(this)
|| state.action == ACTION_OPEN
|| state.action == ACTION_CREATE
@@ -483,6 +486,7 @@
Metrics.logUserAction(this,
display ? Metrics.USER_ACTION_SHOW_ADVANCED : Metrics.USER_ACTION_HIDE_ADVANCED);
+ LocalPreferences.setShowDeviceRoot(this, mState.action, display);
mState.showAdvanced = display;
RootsFragment.get(getFragmentManager()).onDisplayStateChanged();
invalidateOptionsMenu();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java b/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
index 2315664..d2e9885e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
@@ -18,9 +18,6 @@
import static com.android.documentsui.State.MODE_UNKNOWN;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.content.Context;
@@ -28,11 +25,16 @@
import android.os.UserHandle;
import android.preference.PreferenceManager;
+import com.android.documentsui.State.ActionType;
import com.android.documentsui.State.ViewMode;
import com.android.documentsui.model.RootInfo;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
public class LocalPreferences {
private static final String KEY_FILE_SIZE = "fileSize";
+ private static final String INCLUDE_DEVICE_ROOT = "includeDeviceRoot-";
private static final String ROOT_VIEW_MODE_PREFIX = "rootViewMode-";
public static boolean getDisplayFileSize(Context context) {
@@ -48,9 +50,17 @@
getPrefs(context).edit().putBoolean(KEY_FILE_SIZE, display).apply();
}
+ public static boolean getShowDeviceRoot(Context context, @ActionType int action) {
+ return getPrefs(context).getBoolean(INCLUDE_DEVICE_ROOT + action, false);
+ }
+
+ public static void setShowDeviceRoot(
+ Context context, @ActionType int action, boolean display) {
+ getPrefs(context).edit().putBoolean(INCLUDE_DEVICE_ROOT + action, display).apply();
+ }
+
public static void setViewMode(Context context, RootInfo root, @ViewMode int viewMode) {
assert(viewMode != MODE_UNKNOWN);
-
getPrefs(context).edit().putInt(createKey(root), viewMode).apply();
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
index f10af43..53fa3cc4 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
@@ -227,7 +227,7 @@
try {
mBatchSize = calculateSize(mSrcs);
} catch (ResourceException e) {
- Log.w(TAG, "Failed to calculate total size. Copying without progress.");
+ Log.w(TAG, "Failed to calculate total size. Copying without progress.", e);
mBatchSize = -1;
}
@@ -236,25 +236,19 @@
for (int i = 0; i < mSrcs.size() && !isCanceled(); ++i) {
srcInfo = mSrcs.get(i);
- // Guard unsupported recursive operation.
- try {
- if (dstInfo.equals(srcInfo) || isDescendentOf(srcInfo, dstInfo)) {
- throw new ResourceException("Cannot copy to itself recursively.");
- }
- } catch (ResourceException e) {
- Log.e(TAG, e.toString());
- onFileFailed(srcInfo);
- continue;
- }
-
if (DEBUG) Log.d(TAG,
"Copying " + srcInfo.displayName + " (" + srcInfo.derivedUri + ")"
+ " to " + dstInfo.displayName + " (" + dstInfo.derivedUri + ")");
try {
- processDocument(srcInfo, null, dstInfo);
+ if (dstInfo.equals(srcInfo) || isDescendentOf(srcInfo, dstInfo)) {
+ Log.e(TAG, "Skipping recursive copy of " + srcInfo.derivedUri);
+ onFileFailed(srcInfo);
+ } else {
+ processDocument(srcInfo, null, dstInfo);
+ }
} catch (ResourceException e) {
- Log.e(TAG, e.toString());
+ Log.e(TAG, "Failed to copy " + srcInfo.derivedUri, e);
onFileFailed(srcInfo);
}
}
@@ -306,7 +300,7 @@
}
} catch (RemoteException | RuntimeException e) {
Log.e(TAG, "Provider side copy failed for: " + src.derivedUri
- + " due to an exception: " + e);
+ + " due to an exception.", e);
}
// If optimized copy fails, then fallback to byte-by-byte copy.
if (DEBUG) Log.d(TAG, "Fallback to byte-by-byte copy for: " + src.derivedUri);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
index 8f45162..36a0f32 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
@@ -86,7 +86,7 @@
try {
deleteDocument(doc, mSrcParent);
} catch (ResourceException e) {
- Log.e(TAG, "Failed to delete document @ " + doc.derivedUri);
+ Log.e(TAG, "Failed to delete document @ " + doc.derivedUri, e);
onFileFailed(doc);
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
index aaa7596..1118171 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
@@ -98,7 +98,7 @@
}
} catch (RemoteException | RuntimeException e) {
Log.e(TAG, "Provider side move failed for: " + src.derivedUri
- + " due to an exception: " + e);
+ + " due to an exception: ", e);
}
// If optimized move fails, then fallback to byte-by-byte copy.
if (DEBUG) Log.d(TAG, "Fallback to byte-by-byte move for: " + src.derivedUri);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index a8419bf..94d9550 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1040,10 +1040,9 @@
public void onForegroundProfileSwitch(int newProfileId) {
// Ignore.
}
- });
+ }, TAG);
} catch (RemoteException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
+ e.rethrowAsRuntimeException();
}
IntentFilter strongAuthTimeoutFilter = new IntentFilter();
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
index 42ef10e..2f58de5 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
@@ -26,6 +26,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.Loader;
+import android.content.pm.ResolveInfo;
import android.database.DataSetObserver;
import android.net.Uri;
import android.os.Bundle;
@@ -450,20 +451,42 @@
private class EnabledServicesAdapter extends PrintServiceInfoAdapter {
@Override
public void performAction(@IntRange(from = 0) int position) {
- PrintServiceInfo service = (PrintServiceInfo) getItem(position);
+ Intent intent = getAddPrinterIntent((PrintServiceInfo) getItem(position));
+ if (intent != null) {
+ try {
+ startActivity(intent);
+ } catch (ActivityNotFoundException|SecurityException e) {
+ Log.e(LOG_TAG, "Cannot start add printers activity", e);
+ }
+ }
+ }
+
+ /**
+ * Get the intent used to launch the add printers activity.
+ *
+ * @param service The service the printer should be added for
+ *
+ * @return The intent to launch the activity or null if the activity could not be launched.
+ */
+ private Intent getAddPrinterIntent(@NonNull PrintServiceInfo service) {
String addPrinterActivityName = service.getAddPrintersActivityName();
if (!TextUtils.isEmpty(addPrinterActivityName)) {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setComponent(new ComponentName(service.getComponentName().getPackageName(),
- addPrinterActivityName));
+ addPrinterActivityName));
- try {
- startActivity(intent);
- } catch (ActivityNotFoundException e) {
- Log.e(LOG_TAG, "Cannot start add printers activity", e);
+ List<ResolveInfo> resolvedActivities = getPackageManager().queryIntentActivities(
+ intent, 0);
+ if (!resolvedActivities.isEmpty()) {
+ // The activity is a component name, therefore it is one or none.
+ if (resolvedActivities.get(0).activityInfo.exported) {
+ return intent;
+ }
}
}
+
+ return null;
}
@Override
@@ -494,7 +517,7 @@
title.setText(service.getResolveInfo().loadLabel(getPackageManager()));
icon.setImageDrawable(service.getResolveInfo().loadIcon(getPackageManager()));
- if (TextUtils.isEmpty(service.getAddPrintersActivityName())) {
+ if (getAddPrinterIntent(service) == null) {
subtitle.setText(getString(R.string.cannot_add_printer));
} else {
subtitle.setText(getString(R.string.select_to_add_printers));
diff --git a/packages/SettingsLib/res/values/colors.xml b/packages/SettingsLib/res/values/colors.xml
index 796273d..02b7ea6 100644
--- a/packages/SettingsLib/res/values/colors.xml
+++ b/packages/SettingsLib/res/values/colors.xml
@@ -17,5 +17,5 @@
<resources>
<color name="disabled_text_color">#66000000</color> <!-- 38% black -->
- <color name="usage_graph_dots">#455A64</color>
+ <color name="usage_graph_dots">@*android:color/tertiary_device_default_settings</color>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
index 76ba0a7..5791168 100644
--- a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
@@ -24,6 +24,7 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
@@ -162,10 +163,9 @@
intent.putExtra(EXTRA_CONTEXT, backupContext);
}
intent.putExtra(EXTRA_THEME, 1 /* Light, dark action bar */);
- Theme theme = context.getTheme();
- TypedValue typedValue = new TypedValue();
- theme.resolveAttribute(android.R.attr.colorPrimary, typedValue, true);
- intent.putExtra(EXTRA_PRIMARY_COLOR, context.getColor(typedValue.resourceId));
+ TypedArray array = context.obtainStyledAttributes(new int[]{android.R.attr.colorPrimary});
+ intent.putExtra(EXTRA_PRIMARY_COLOR, array.getColor(0, 0));
+ array.recycle();
}
/**
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index d98f1a4..7993131 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -1,5 +1,6 @@
package com.android.settingslib;
+import android.annotation.ColorInt;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
@@ -8,6 +9,7 @@
import android.content.pm.UserInfo;
import android.content.pm.Signature;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
@@ -154,6 +156,14 @@
return statusString;
}
+ @ColorInt
+ public static int getColorAccent(Context context) {
+ TypedArray ta = context.obtainStyledAttributes(new int[]{android.R.attr.colorAccent});
+ @ColorInt int colorAccent = ta.getColor(0, 0);
+ ta.recycle();
+ return colorAccent;
+ }
+
/**
* Determine whether a package is a "system package", in which case certain things (like
* disabling notifications or disabling the package altogether) should be disallowed.
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java b/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
index 8512dca..f4f7986 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
@@ -76,6 +76,8 @@
bundle.putParcelable(Settings.CALL_METHOD_TRACK_GENERATION_KEY,
backingStore);
bundle.putInt(Settings.CALL_METHOD_GENERATION_INDEX_KEY, index);
+ bundle.putInt(Settings.CALL_METHOD_GENERATION_KEY,
+ backingStore.get(index));
if (DEBUG) {
Slog.i(LOG_TAG, "Exported index:" + index + " for key:"
+ SettingsProvider.keyToString(key));
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 25dc357..809774b 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -165,6 +165,9 @@
<!-- the ability to rename notifications posted by other apps -->
<uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
+ <!-- shortcut manager -->
+ <uses-permission android:name="android.permission.RESET_SHORTCUT_MANAGER_THROTTLING" />
+
<application
android:name=".SystemUIApplication"
android:persistent="true"
diff --git a/packages/SystemUI/res/color/notification_guts_buttons.xml b/packages/SystemUI/res/color/notification_guts_buttons.xml
index c211e43..3b8d59b 100644
--- a/packages/SystemUI/res/color/notification_guts_buttons.xml
+++ b/packages/SystemUI/res/color/notification_guts_buttons.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true"
- android:color="@*android:color/material_deep_teal_500" />
+ android:color="?android:attr/colorAccent" />
<item android:color="@android:color/black"
android:alpha=".54" />
</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/fab_background.xml b/packages/SystemUI/res/color/qs_detail_progress_track.xml
similarity index 62%
copy from packages/SystemUI/res/drawable/fab_background.xml
copy to packages/SystemUI/res/color/qs_detail_progress_track.xml
index 7f23f2b..c56382e 100644
--- a/packages/SystemUI/res/drawable/fab_background.xml
+++ b/packages/SystemUI/res/color/qs_detail_progress_track.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 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.
@@ -13,11 +13,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="@color/fab_ripple">
- <item>
- <shape>
- <solid android:color="@color/fab_shape" />
- </shape>
- </item>
-</ripple>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- I really don't want to define this, but the View that uses this asset uses both the
+ light and dark accent colors. -->
+ <item android:alpha="0.6" android:drawable="@*android:color/accent_device_default_light" />
+</selector>
diff --git a/packages/SystemUI/res/color/qs_user_detail_avatar_frame.xml b/packages/SystemUI/res/color/qs_user_detail_avatar_frame.xml
index 20251c2..344859c 100644
--- a/packages/SystemUI/res/color/qs_user_detail_avatar_frame.xml
+++ b/packages/SystemUI/res/color/qs_user_detail_avatar_frame.xml
@@ -17,6 +17,6 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_activated="true" android:color="@color/current_user_border_color" />
+ <item android:state_activated="true" android:color="?android:attr/colorAccent" />
<item android:color="@android:color/transparent" />
</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/color/qs_user_detail_name.xml b/packages/SystemUI/res/color/qs_user_detail_name.xml
index 35c7a4f..e262209 100644
--- a/packages/SystemUI/res/color/qs_user_detail_name.xml
+++ b/packages/SystemUI/res/color/qs_user_detail_name.xml
@@ -17,7 +17,7 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_activated="true" android:color="@color/current_user_border_color" />
+ <item android:state_activated="true" android:color="?android:attr/colorAccent" />
<item android:state_enabled="false" android:color="@color/qs_tile_disabled_color" />
<item android:color="#66ffffff" /> <!-- 40% white -->
</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/fab_background.xml b/packages/SystemUI/res/color/screen_pinning_nav_icon_highlight_outer.xml
similarity index 67%
rename from packages/SystemUI/res/drawable/fab_background.xml
rename to packages/SystemUI/res/color/screen_pinning_nav_icon_highlight_outer.xml
index 7f23f2b..5370f7a 100644
--- a/packages/SystemUI/res/drawable/fab_background.xml
+++ b/packages/SystemUI/res/color/screen_pinning_nav_icon_highlight_outer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 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.
@@ -13,11 +13,6 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="@color/fab_ripple">
- <item>
- <shape>
- <solid android:color="@color/fab_shape" />
- </shape>
- </item>
-</ripple>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:alpha="0.25" android:color="?android:attr/colorAccent" />
+</selector>
diff --git a/packages/SystemUI/res/drawable/brightness_mirror_background.xml b/packages/SystemUI/res/drawable/brightness_mirror_background.xml
index e901e40..0c69d89 100644
--- a/packages/SystemUI/res/drawable/brightness_mirror_background.xml
+++ b/packages/SystemUI/res/drawable/brightness_mirror_background.xml
@@ -15,5 +15,5 @@
~ limitations under the License
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="@color/system_primary_color" />
+ <solid android:color="?android:attr/colorPrimary" />
</shape>
diff --git a/packages/SystemUI/res/drawable/ic_brightness_thumb.xml b/packages/SystemUI/res/drawable/ic_brightness_thumb.xml
index dc978fe..24ac018 100644
--- a/packages/SystemUI/res/drawable/ic_brightness_thumb.xml
+++ b/packages/SystemUI/res/drawable/ic_brightness_thumb.xml
@@ -20,7 +20,7 @@
android:viewportHeight="24.0">
<path
android:pathData="m18.250000,12.000000a6.250000,6.250000 0.000000,1.000000 1.000000,-12.500000 0.000000,6.250000 6.250000,0.000000 1.000000,1.000000 12.500000,0.000000z"
- android:fillColor="@color/system_primary_color" />
+ android:fillColor="?android:attr/colorPrimary" />
<path
android:fillColor="#FFFFFFFF"
android:pathData="M20.000000,8.700000L20.000000,4.000000L15.300000,4.000000L12.000000,0.700000 8.700000,4.000000L4.000000,4.000000L4.000000,8.700000L0.700000,12.000000 4.000000,15.300000L4.000000,20.000000L8.700000,20.000000L12.000000,23.299999 15.300000,20.000000L20.000000,20.000000L20.000000,15.300000L23.299999,12.000000 20.000000,8.700000zM12.000000,18.000000C8.700000,18.000000 6.000000,15.300000 6.000000,12.000000 6.000000,8.700000 8.700000,6.000000 12.000000,6.000000c3.300000,0.000000 6.000000,2.700000 6.000000,6.000000 0.000000,3.300000 -2.700000,6.000000 -6.000000,6.000000zM12.000000,8.000000c-2.200000,0.000000 -4.000000,1.800000 -4.000000,4.000000 0.000000,2.200000 1.800000,4.000000 4.000000,4.000000 2.200000,0.000000 4.000000,-1.800000 4.000000,-4.000000 0.000000,-2.200000 -1.800000,-4.000000 -4.000000,-4.000000z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml b/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml
new file mode 100644
index 0000000..258bd0f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml
@@ -0,0 +1,37 @@
+<!--
+ 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="18.0dp"
+ android:height="24dp"
+ android:viewportWidth="36.0"
+ android:viewportHeight="36.0">
+
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M6.797,13.334h1.231v1.522H6.797v2.509h-1.62v-2.509H1.101l-0.039-1.157l4.069-7.643h1.666V13.334z
+M2.648,13.334h2.53V8.721L5.137,8.713L4.984,9.148L2.648,13.334z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M16.155,15.836c-0.269,0.439-0.695,0.832-1.282,1.177c-0.587,0.344-1.344,0.517-2.271,0.517
+c-1.151,0-2.098-0.432-2.841-1.294c-0.744-0.862-1.115-1.978-1.115-3.345v-2.36c0-1.367,0.359-2.481,1.077-3.343
+c0.719-0.863,1.643-1.293,2.772-1.293c1.132,0,2.017,0.331,2.649,0.994c0.633,0.663,0.941,1.528,0.924,2.594l-0.021,0.047h-1.545
+c0-0.638-0.171-1.15-0.513-1.538c-0.341-0.389-0.831-0.583-1.469-0.583c-0.674,0-1.217,0.292-1.63,0.877
+c-0.413,0.585-0.619,1.328-0.619,2.229v2.375c0,0.912,0.215,1.662,0.645,2.25c0.431,0.587,0.992,0.881,1.684,0.881
+c0.522,0,0.935-0.068,1.238-0.205c0.304-0.138,0.533-0.305,0.688-0.502v-2.338h-2.041v-1.413h3.668V15.836z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M19.366,14.701v-2.232h-2.25v-1.541h2.25V8.695h1.5v2.232h2.256v1.541h-2.256v2.232H19.366z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/notification_header_bg.xml b/packages/SystemUI/res/drawable/notification_header_bg.xml
deleted file mode 100644
index 1f46502..0000000
--- a/packages/SystemUI/res/drawable/notification_header_bg.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 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
- -->
-
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="?android:attr/colorControlHighlight" >
- <item android:drawable="@color/system_secondary_color"/>
-</ripple>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_background_primary.xml b/packages/SystemUI/res/drawable/qs_background_primary.xml
index 1bf7d4c..8ea9e06 100644
--- a/packages/SystemUI/res/drawable/qs_background_primary.xml
+++ b/packages/SystemUI/res/drawable/qs_background_primary.xml
@@ -15,6 +15,6 @@
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android">
<shape>
- <solid android:color="@color/system_primary_color"/>
+ <solid android:color="?android:attr/colorPrimary"/>
</shape>
</inset>
diff --git a/packages/SystemUI/res/drawable/qs_customizer_background.xml b/packages/SystemUI/res/drawable/qs_customizer_background.xml
index d90f820..12d8016 100644
--- a/packages/SystemUI/res/drawable/qs_customizer_background.xml
+++ b/packages/SystemUI/res/drawable/qs_customizer_background.xml
@@ -15,5 +15,5 @@
-->
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/qs_detail_transition" />
- <item android:drawable="@color/system_primary_color" />
+ <item android:drawable="?android:attr/colorPrimary" />
</transition>
diff --git a/packages/SystemUI/res/drawable/qs_detail_background.xml b/packages/SystemUI/res/drawable/qs_detail_background.xml
index 692cd44..84c793f 100644
--- a/packages/SystemUI/res/drawable/qs_detail_background.xml
+++ b/packages/SystemUI/res/drawable/qs_detail_background.xml
@@ -15,5 +15,5 @@
-->
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/qs_detail_transition" />
- <item android:drawable="@color/system_primary_color" />
+ <item android:drawable="?android:attr/colorPrimary" />
</transition>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/quick_header_bg.xml b/packages/SystemUI/res/drawable/quick_header_bg.xml
index d45d673..920e6f5 100644
--- a/packages/SystemUI/res/drawable/quick_header_bg.xml
+++ b/packages/SystemUI/res/drawable/quick_header_bg.xml
@@ -17,5 +17,5 @@
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight" >
- <item android:drawable="@color/system_primary_color"/>
+ <item android:drawable="?android:attr/colorPrimary"/>
</ripple>
diff --git a/packages/SystemUI/res/drawable/screen_pinning_bg_circ.xml b/packages/SystemUI/res/drawable/screen_pinning_bg_circ.xml
index 354b8bd..1303bdb 100644
--- a/packages/SystemUI/res/drawable/screen_pinning_bg_circ.xml
+++ b/packages/SystemUI/res/drawable/screen_pinning_bg_circ.xml
@@ -19,7 +19,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval" >
- <solid android:color="@color/system_accent_color" />
+ <solid android:color="?android:attr/colorAccent" />
<size
android:height="@dimen/screen_pinning_nav_highlight_size"
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml
new file mode 100644
index 0000000..17a4394
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml
@@ -0,0 +1,37 @@
+<!--
+ 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="15dp"
+ android:height="20dp"
+ android:viewportWidth="36"
+ android:viewportHeight="36">
+
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M6.797,13.334h1.231v1.522H6.797v2.509h-1.62v-2.509H1.101l-0.039-1.157l4.069-7.643h1.666V13.334z
+M2.648,13.334h2.53V8.721L5.137,8.713L4.984,9.148L2.648,13.334z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M16.155,15.836c-0.269,0.439-0.695,0.832-1.282,1.177c-0.587,0.344-1.344,0.517-2.271,0.517
+c-1.151,0-2.098-0.432-2.841-1.294c-0.744-0.862-1.115-1.978-1.115-3.345v-2.36c0-1.367,0.359-2.481,1.077-3.343
+c0.719-0.863,1.643-1.293,2.772-1.293c1.132,0,2.017,0.331,2.649,0.994c0.633,0.663,0.941,1.528,0.924,2.594l-0.021,0.047h-1.545
+c0-0.638-0.171-1.15-0.513-1.538c-0.341-0.389-0.831-0.583-1.469-0.583c-0.674,0-1.217,0.292-1.63,0.877
+c-0.413,0.585-0.619,1.328-0.619,2.229v2.375c0,0.912,0.215,1.662,0.645,2.25c0.431,0.587,0.992,0.881,1.684,0.881
+c0.522,0,0.935-0.068,1.238-0.205c0.304-0.138,0.533-0.305,0.688-0.502v-2.338h-2.041v-1.413h3.668V15.836z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M19.366,14.701v-2.232h-2.25v-1.541h2.25V8.695h1.5v2.232h2.256v1.541h-2.256v2.232H19.366z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/switchbar_background.xml b/packages/SystemUI/res/drawable/switchbar_background.xml
index 8d97c46..fb59633 100644
--- a/packages/SystemUI/res/drawable/switchbar_background.xml
+++ b/packages/SystemUI/res/drawable/switchbar_background.xml
@@ -16,6 +16,6 @@
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight">
- <item android:drawable="@color/switch_bar_background" />
+ <item android:drawable="?android:attr/colorSecondary" />
</ripple>
diff --git a/packages/SystemUI/res/drawable/volume_dialog_background.xml b/packages/SystemUI/res/drawable/volume_dialog_background.xml
index e98bfb8..d6adea9 100644
--- a/packages/SystemUI/res/drawable/volume_dialog_background.xml
+++ b/packages/SystemUI/res/drawable/volume_dialog_background.xml
@@ -14,5 +14,5 @@
limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
- <solid android:color="@color/system_primary_color" />
+ <solid android:color="?android:attr/colorPrimary" />
</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/zen_introduction_message_background.xml b/packages/SystemUI/res/drawable/zen_introduction_message_background.xml
index 352fb57..e5b41a3 100644
--- a/packages/SystemUI/res/drawable/zen_introduction_message_background.xml
+++ b/packages/SystemUI/res/drawable/zen_introduction_message_background.xml
@@ -17,6 +17,6 @@
<corners android:radius="@dimen/borderless_button_radius" />
- <solid android:color="@color/zen_introduction_message_background" />
+ <solid android:color="?android:attr/colorAccent" />
</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml b/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml
index 52cab72..69e52c5 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml
@@ -53,5 +53,6 @@
android:layout_alignParentEnd="true"
android:textSize="14sp"
android:scrollHorizontally="false"
- android:layout_centerVertical="true"/>
+ android:layout_centerVertical="true"
+ android:focusable="true"/>
</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_icon_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_icon_view.xml
index 5db6789..a3901d0 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_key_icon_view.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_icon_view.xml
@@ -21,4 +21,4 @@
android:padding="@dimen/ksh_item_padding"
android:layout_marginStart="@dimen/ksh_item_margin_start"
android:scaleType="fitXY"
- android:background="@drawable/ksh_key_item_background"/>
+ android:background="@drawable/ksh_key_item_background" />
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml
index 31a8773..b06f7fc 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml
@@ -23,4 +23,5 @@
android:textColor="@color/ksh_key_item_color"
android:singleLine="true"
android:gravity="center"
- android:textSize="@dimen/ksh_item_text_size"/>
+ android:textSize="@dimen/ksh_item_text_size"
+ android:textAllCaps="true"/>
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index d09c42b..e84ed23 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -26,7 +26,8 @@
android:orientation="vertical"
android:paddingStart="@*android:dimen/notification_content_margin_start"
android:paddingEnd="8dp"
- android:background="@color/notification_guts_bg_color">
+ android:background="@color/notification_guts_bg_color"
+ android:theme="@*android:style/Theme.DeviceDefault.Light">
<!-- header -->
<LinearLayout
@@ -145,8 +146,8 @@
android:focusable="true"
android:background="#00ffffff"
android:progressBackgroundTint="@color/notification_guts_secondary_slider_color"
- android:thumbTint="@color/notification_guts_slider_color"
- android:progressTint="@color/notification_guts_slider_color"
+ android:thumbTint="?android:attr/colorAccent"
+ android:progressTint="?android:attr/colorAccent"
style="@android:style/Widget.Material.SeekBar.Discrete"
android:tickMarkTint="@android:color/black" />
diff --git a/packages/SystemUI/res/layout/screen_pinning_request.xml b/packages/SystemUI/res/layout/screen_pinning_request.xml
index fea45cc..d55ba94 100644
--- a/packages/SystemUI/res/layout/screen_pinning_request.xml
+++ b/packages/SystemUI/res/layout/screen_pinning_request.xml
@@ -21,7 +21,8 @@
android:layout_height="wrap_content"
android:gravity="bottom|center_horizontal"
android:layoutDirection="ltr"
- android:orientation="vertical" >
+ android:orientation="vertical"
+ android:theme="@android:style/Theme.DeviceDefault.Light">
<include
android:layout_width="@dimen/screen_pinning_request_width"
@@ -32,7 +33,7 @@
android:id="@+id/spacer"
android:layout_width="@dimen/screen_pinning_request_width"
android:layout_height="18dp"
- android:background="@color/screen_pinning_request_bg" />
+ android:background="?android:attr/colorAccent" />
<include
android:layout_width="@dimen/screen_pinning_request_width"
diff --git a/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml b/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml
index 60112be..e3662f17 100644
--- a/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml
+++ b/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml
@@ -28,7 +28,7 @@
android:id="@+id/screen_pinning_buttons"
android:layout_width="match_parent"
android:layout_height="@dimen/screen_pinning_request_button_height"
- android:background="@color/screen_pinning_request_bg" >
+ android:background="?android:attr/colorAccent">
<View
android:layout_width="@dimen/screen_pinning_request_side_width"
@@ -42,7 +42,8 @@
android:layout_height="@dimen/screen_pinning_request_button_height"
android:layout_weight="0"
android:paddingStart="@dimen/screen_pinning_request_frame_padding"
- android:paddingEnd="@dimen/screen_pinning_request_frame_padding" >
+ android:paddingEnd="@dimen/screen_pinning_request_frame_padding"
+ android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent">
<ImageView
android:id="@+id/screen_pinning_back_bg_light"
diff --git a/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml b/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml
index ebad7a4..3649ffb 100644
--- a/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml
+++ b/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml
@@ -25,8 +25,8 @@
android:id="@+id/screen_pinning_buttons"
android:layout_height="match_parent"
android:layout_width="@dimen/screen_pinning_request_button_height"
- android:background="@color/screen_pinning_request_bg"
- android:orientation="vertical" >
+ android:background="?android:attr/colorAccent"
+ android:orientation="vertical">
<View
android:layout_height="@dimen/screen_pinning_request_side_width"
@@ -82,7 +82,8 @@
android:id="@+id/screen_pinning_back_group"
android:layout_height="@dimen/screen_pinning_request_button_width"
android:layout_width="@dimen/screen_pinning_request_button_height"
- android:layout_weight="0" >
+ android:layout_weight="0"
+ android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent">
<ImageView
android:id="@+id/screen_pinning_back_bg_light"
diff --git a/packages/SystemUI/res/layout/screen_pinning_request_land_phone.xml b/packages/SystemUI/res/layout/screen_pinning_request_land_phone.xml
index e6c22d4..ec16991 100644
--- a/packages/SystemUI/res/layout/screen_pinning_request_land_phone.xml
+++ b/packages/SystemUI/res/layout/screen_pinning_request_land_phone.xml
@@ -20,7 +20,8 @@
android:layout_height="@dimen/screen_pinning_request_width"
android:layout_width="wrap_content"
android:gravity="right|center_vertical"
- android:orientation="horizontal" >
+ android:orientation="horizontal"
+ android:theme="@android:style/Theme.DeviceDefault.Light">
<include
android:layout_width="360dp"
diff --git a/packages/SystemUI/res/layout/screen_pinning_request_text_area.xml b/packages/SystemUI/res/layout/screen_pinning_request_text_area.xml
index df957f4..cdad94b 100644
--- a/packages/SystemUI/res/layout/screen_pinning_request_text_area.xml
+++ b/packages/SystemUI/res/layout/screen_pinning_request_text_area.xml
@@ -20,8 +20,8 @@
android:id="@+id/screen_pinning_text_area"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:background="@color/screen_pinning_request_bg"
- android:gravity="center_vertical" >
+ android:background="?android:attr/colorAccent"
+ android:gravity="center_vertical">
<TextView
android:id="@+id/screen_pinning_title"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
deleted file mode 100644
index c5cd65e..0000000
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ /dev/null
@@ -1,195 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-** Copyright 2012, 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.
--->
-
-<!-- Extends RelativeLayout -->
-<com.android.systemui.statusbar.phone.StatusBarHeaderView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:id="@+id/header"
- android:layout_width="@dimen/notification_panel_width"
- android:layout_height="@dimen/status_bar_header_height"
- android:layout_gravity="@integer/notification_panel_layout_gravity"
- android:baselineAligned="false"
- android:elevation="4dp"
- android:background="@drawable/notification_header_bg"
- android:clickable="true"
- android:focusable="true"
- >
-
- <com.android.systemui.statusbar.phone.MultiUserSwitch android:id="@+id/multi_user_switch"
- android:layout_width="@dimen/multi_user_switch_width_collapsed"
- android:layout_height="@dimen/status_bar_header_height"
- android:layout_alignParentEnd="true"
- android:background="@drawable/ripple_drawable" >
- <ImageView android:id="@+id/multi_user_avatar"
- android:layout_width="@dimen/multi_user_avatar_expanded_size"
- android:layout_height="@dimen/multi_user_avatar_expanded_size"
- android:layout_gravity="center"
- android:scaleType="centerInside"/>
- </com.android.systemui.statusbar.phone.MultiUserSwitch>
-
- <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
- android:id="@+id/settings_button_container"
- android:layout_width="48dp"
- android:layout_height="@dimen/status_bar_header_height"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:layout_toStartOf="@id/multi_user_switch">
-
- <com.android.systemui.statusbar.phone.SettingsButton android:id="@+id/settings_button"
- style="@android:style/Widget.Material.Button.Borderless"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/ripple_drawable"
- android:src="@drawable/ic_settings"
- android:contentDescription="@string/accessibility_desc_settings" />
- <com.android.systemui.statusbar.AlphaOptimizedImageView android:id="@+id/tuner_icon"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingStart="36dp"
- android:tint="#4DFFFFFF"
- android:tintMode="src_in"
- android:visibility="invisible"
- android:src="@drawable/tuner" />
-
- </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
-
- <LinearLayout android:id="@+id/system_icons_super_container"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/status_bar_header_height"
- android:layout_toStartOf="@id/multi_user_switch"
- android:layout_alignWithParentIfMissing="true"
- android:layout_marginStart="16dp"
- android:background="@drawable/ripple_drawable"
- android:paddingEnd="4dp" >
- <FrameLayout android:id="@+id/system_icons_container"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/status_bar_height"
- android:layout_gravity="center_vertical"
- >
- <include layout="@layout/system_icons" />
- </FrameLayout>
- <TextView android:id="@+id/battery_level"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginStart="@dimen/header_battery_margin_expanded"
- android:paddingEnd="@dimen/battery_level_padding_end"
- android:textColor="#ffffff"
- android:textSize="@dimen/battery_level_text_size"
- android:importantForAccessibility="noHideDescendants"/>
- </LinearLayout>
-
- <TextView
- android:id="@+id/header_emergency_calls_only"
- android:layout_height="@dimen/status_bar_header_height"
- android:layout_width="wrap_content"
- android:layout_alignParentStart="true"
- android:layout_toStartOf="@id/system_icons_super_container"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
- android:visibility="gone"
- android:textAppearance="@style/TextAppearance.StatusBar.Expanded.EmergencyCallsOnly"
- android:text="@*android:string/emergency_calls_only"
- android:singleLine="true"
- android:gravity="center_vertical" />
-
- <FrameLayout
- android:id="@+id/date_group"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/clock_collapsed_bottom_margin"
- android:layout_alignParentBottom="true">
- <com.android.systemui.statusbar.policy.DateView android:id="@+id/date_collapsed"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="16dp"
- android:singleLine="true"
- android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
- android:layout_below="@id/clock"
- systemui:datePattern="@string/abbrev_wday_month_day_no_year_alarm"
- />
-
- <com.android.systemui.statusbar.policy.DateView android:id="@+id/date_expanded"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="16dp"
- android:singleLine="true"
- android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
- android:layout_below="@id/clock"
- systemui:datePattern="eeeeMMMMd"
- />
- </FrameLayout>
-
- <include layout="@layout/split_clock_view"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="16dp"
- android:layout_above="@id/date_group"
- android:id="@+id/clock"
- />
-
- <com.android.systemui.statusbar.AlphaOptimizedButton android:id="@+id/alarm_status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_toEndOf="@id/date_group"
- android:layout_marginBottom="4dp"
- android:drawablePadding="6dp"
- android:drawableStart="@drawable/ic_access_alarms_small"
- android:textColor="#64ffffff"
- android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
- android:paddingEnd="6dp"
- android:paddingStart="6dp"
- android:paddingTop="16dp"
- android:paddingBottom="16dp"
- android:background="?android:attr/selectableItemBackground"
- android:visibility="gone"
- />
-
- <include
- android:id="@+id/qs_detail_header"
- layout="@layout/qs_detail_header"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- />
-
- <com.android.systemui.statusbar.AlphaOptimizedImageView
- android:id="@+id/qs_detail_header_progress"
- android:src="@drawable/indeterminate_anim"
- android:alpha="0"
- android:background="@color/qs_detail_progress_track"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- />
-
- <TextView
- android:id="@+id/header_debug_info"
- android:visibility="invisible"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:fontFamily="sans-serif-condensed"
- android:textSize="11dp"
- android:textStyle="bold"
- android:textColor="#00A040"
- android:padding="2dp"
- />
-
-</com.android.systemui.statusbar.phone.StatusBarHeaderView>
diff --git a/packages/SystemUI/res/layout/switch_bar.xml b/packages/SystemUI/res/layout/switch_bar.xml
index f98de96..41cdb78 100644
--- a/packages/SystemUI/res/layout/switch_bar.xml
+++ b/packages/SystemUI/res/layout/switch_bar.xml
@@ -22,7 +22,8 @@
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:clickable="true"
- android:gravity="center">
+ android:gravity="center"
+ android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent">
<TextView android:id="@+id/switch_text"
android:layout_height="wrap_content"
@@ -42,7 +43,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
- android:background="@null"
- android:theme="@style/ThemeOverlay.SwitchBar" />
+ android:background="@null" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/tile_listing.xml b/packages/SystemUI/res/layout/tile_listing.xml
deleted file mode 100644
index 9ab62ca..0000000
--- a/packages/SystemUI/res/layout/tile_listing.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ** Copyright 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.
- -->
-
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="@drawable/qs_background_primary"
- android:paddingBottom="20dp"
- android:orientation="vertical">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="@drawable/notification_header_bg"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:paddingTop="10dp"
- android:paddingBottom="10dp"
- android:orientation="horizontal">
- <ImageView
- android:id="@android:id/icon"
- android:layout_width="36dp"
- android:layout_height="36dp" />
- <TextView
- android:id="@android:id/title"
- android:paddingStart="10dp"
- android:textColor="@android:color/white"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical" />
- </LinearLayout>
-
- <GridLayout
- android:id="@+id/tile_grid"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:columnCount="4" />
-
- </LinearLayout>
diff --git a/packages/SystemUI/res/layout/tuner_qs.xml b/packages/SystemUI/res/layout/tuner_qs.xml
deleted file mode 100644
index 9a51e0c..0000000
--- a/packages/SystemUI/res/layout/tuner_qs.xml
+++ /dev/null
@@ -1,47 +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.
--->
-
-<com.android.systemui.tuner.AutoScrollView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@color/system_secondary_color" >
- <LinearLayout
- android:id="@+id/all_details"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:gravity="center"
- android:orientation="vertical">
-
- <View
- android:background="@color/qs_tile_divider"
- android:layout_width="match_parent"
- android:layout_height="2dp" />
-
- <FrameLayout
- android:id="@+id/remove_target"
- android:layout_width="105dp"
- android:layout_height="@dimen/qs_tile_height" />
-
- <FrameLayout
- android:id="@+id/add_target"
- android:layout_width="105dp"
- android:layout_height="@dimen/qs_tile_height" />
- </LinearLayout>
-</com.android.systemui.tuner.AutoScrollView>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index d3f2a25..68395cd 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -20,16 +20,14 @@
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/volume_dialog_margin_bottom"
android:background="@drawable/volume_dialog_background"
- android:translationZ="4dp"
- android:paddingTop="8dp">
+ android:translationZ="4dp" >
<LinearLayout
android:id="@+id/volume_dialog_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:paddingBottom="8dp"
- android:paddingStart="8dp"
+ android:paddingTop="@dimen/volume_dialog_collapsed_padding_top"
android:animateLayoutChanges="true" >
<!-- volume rows added and removed here! :-) -->
@@ -52,6 +50,8 @@
android:src="@drawable/ic_volume_collapse_animation"
tools:ignore="RtlHardcoded"
android:layout_alignParentEnd="true"
- android:layout_alignParentTop="true"/>
+ android:layout_alignParentTop="true"
+ android:layout_marginTop="@dimen/volume_expander_margin_top"
+ android:layout_marginEnd="@dimen/volume_expander_margin_end"/>
</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index be05a3a..a30fc43 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -13,14 +13,16 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<RelativeLayout
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="@dimen/volume_row_height"
android:clipChildren="false"
android:clipToPadding="false"
android:id="@+id/volume_dialog_row"
- android:paddingEnd="@dimen/volume_button_size" >
+ android:paddingEnd="@dimen/volume_dialog_padding_end"
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/volume_row_padding_bottom" >
<TextView
android:id="@+id/volume_row_header"
@@ -29,32 +31,28 @@
android:ellipsize="end"
android:maxLines="1"
android:textAppearance="@style/TextAppearance.Volume.Header"
- android:paddingBottom="0dp"
- android:paddingEnd="12dp"
- android:paddingStart="12dp"
- android:paddingTop="4dp"
- android:visibility="gone" />
+ android:paddingStart="@dimen/volume_row_header_padding_start" />
- <com.android.keyguard.AlphaOptimizedImageButton
- android:id="@+id/volume_row_icon"
- style="@style/VolumeButtons"
- android:layout_width="@dimen/volume_button_size"
- android:layout_height="@dimen/volume_button_size"
- android:layout_below="@id/volume_row_header"
- android:soundEffectsEnabled="false" />
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/volume_row_slider_height"
+ android:orientation="horizontal"
+ android:paddingStart="@dimen/volume_row_padding_start" >
+ <com.android.keyguard.AlphaOptimizedImageButton
+ android:id="@+id/volume_row_icon"
+ style="@style/VolumeButtons"
+ android:layout_width="@dimen/volume_button_size"
+ android:layout_height="@dimen/volume_button_size"
+ android:soundEffectsEnabled="false" />
- <SeekBar
- android:id="@+id/volume_row_slider"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignBottom="@+id/volume_row_icon"
- android:layout_alignWithParentIfMissing="true"
- android:layout_below="@id/volume_row_header"
- android:layout_toEndOf="@id/volume_row_icon"
- android:layout_toStartOf="@+id/volume_settings_button"
- android:focusable="true"
- android:focusableInTouchMode="true"
- android:paddingEnd="8dp"
- android:paddingStart="8dp" />
+ <SeekBar
+ android:id="@+id/volume_row_slider"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignWithParentIfMissing="true"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:paddingStart="@dimen/volume_row_slider_padding_start"/>
+ </LinearLayout>
-</RelativeLayout>
\ No newline at end of file
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_zen_footer.xml b/packages/SystemUI/res/layout/volume_zen_footer.xml
index f30023d..ea26bba 100644
--- a/packages/SystemUI/res/layout/volume_zen_footer.xml
+++ b/packages/SystemUI/res/layout/volume_zen_footer.xml
@@ -78,7 +78,7 @@
android:paddingStart="15dp"
android:paddingEnd="15dp"
android:text="@string/volume_zen_end_now"
- android:textColor="@color/system_accent_color"
+ android:textColor="?android:attr/colorAccent"
android:textAppearance="@style/TextAppearance.QS.DetailButton" />
</com.android.systemui.volume.ZenFooter>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/zen_mode_panel.xml b/packages/SystemUI/res/layout/zen_mode_panel.xml
index 906b867..c0be676 100644
--- a/packages/SystemUI/res/layout/zen_mode_panel.xml
+++ b/packages/SystemUI/res/layout/zen_mode_panel.xml
@@ -40,7 +40,8 @@
android:layout_marginEnd="16dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
- android:background="@drawable/zen_introduction_message_background" >
+ android:background="@drawable/zen_introduction_message_background"
+ android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent.Light">
<ImageView
android:id="@+id/zen_introduction_confirm"
diff --git a/packages/SystemUI/res/values-af/strings_tv.xml b/packages/SystemUI/res/values-af/strings_tv.xml
index 6b28cfd..f90c426 100644
--- a/packages/SystemUI/res/values-af/strings_tv.xml
+++ b/packages/SystemUI/res/values-af/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Dit hou jou video in sig totdat jy \'n ander een speel. Druk en hou "<b>"HOME"</b>" om dit te beheer."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Het dit"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Maak toe"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings_tv.xml b/packages/SystemUI/res/values-am/strings_tv.xml
index c4a47e3..493ae48f 100644
--- a/packages/SystemUI/res/values-am/strings_tv.xml
+++ b/packages/SystemUI/res/values-am/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"ይሄ ሌላ እስኪያጫውቱ ድረስ ቪዲዮዎን በእይታ ውስጥ እንዳለ ያቆየዋል። እሱን ለመቆጣጠር "<b>"መነሻ"</b>"ን ተጭነው ይያዙት።"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"ገባኝ"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"አሰናብት"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings_tv.xml b/packages/SystemUI/res/values-ar/strings_tv.xml
index 081e4e3..f8cbe54 100644
--- a/packages/SystemUI/res/values-ar/strings_tv.xml
+++ b/packages/SystemUI/res/values-ar/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"يؤدي هذا إلى الاحتفاظ بعرض الفيديو إلى أن يتم تشغيل فيديو آخر. اضغط مع الاستمرار على زر "<b>"الشاشة الرئيسية"</b>" للتحكم في هذا الإعداد."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"حسنًا"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"رفض"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings_tv.xml b/packages/SystemUI/res/values-az-rAZ/strings_tv.xml
index 6b0a18e..94e61f1 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings_tv.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Digərini oxudana kimi videonuzu görünən edir. Nəzarət etmək üçün "<b>"ƏSAS SƏHİFƏ"</b>" düyməsini basıb saxlayın."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Anladım"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Rədd edin"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings_tv.xml b/packages/SystemUI/res/values-bg/strings_tv.xml
index a943261..17038ad 100644
--- a/packages/SystemUI/res/values-bg/strings_tv.xml
+++ b/packages/SystemUI/res/values-bg/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Видеоклипът ви ще остане видим, докато не пуснете друг. Натиснете и задръжте "<b>"HOME"</b>", за да контролирате функцията."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Разбрах"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Отхвърляне"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings_tv.xml b/packages/SystemUI/res/values-bn-rBD/strings_tv.xml
index c61dc83..99eb537 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings_tv.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"আপনি অন্য একটি না প্লে করা পর্যন্ত এটি আপনার ভিডিও দেখা বজায় রাখে৷ এটিকে নিয়ন্ত্রণ করতে "<b>"হোম"</b>" টিপুন এবং ধরে রাখুন৷"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"বুঝেছি"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"খারিজ করুন"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings_tv.xml b/packages/SystemUI/res/values-ca/strings_tv.xml
index 0a3e220..bc094a9 100644
--- a/packages/SystemUI/res/values-ca/strings_tv.xml
+++ b/packages/SystemUI/res/values-ca/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Amb aquesta opció el vídeo continua veient-se fins que en reprodueixes un altre. Mantén premut el botó "<b>"INICI"</b>" per controlar-la."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"D\'acord"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Ignora"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 2f5d97c..68ce2cb 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -72,7 +72,7 @@
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Ukládání snímku obrazovky..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Ukládání snímku obrazovky..."</string>
<string name="screenshot_saving_text" msgid="2419718443411738818">"Probíhá ukládání snímku obrazovky."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Snímek obrazovky Snímek obrazovky pořízen."</string>
+ <string name="screenshot_saved_title" msgid="6461865960961414961">"Snímek obrazovky pořízen"</string>
<string name="screenshot_saved_text" msgid="2685605830386712477">"Klepnutím zobrazíte snímek obrazovky."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Snímek obrazovky se nepodařilo zachytit."</string>
<string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Při ukládání snímku obrazovky došlo k problému."</string>
diff --git a/packages/SystemUI/res/values-cs/strings_tv.xml b/packages/SystemUI/res/values-cs/strings_tv.xml
index 731ff5a..459b8bc 100644
--- a/packages/SystemUI/res/values-cs/strings_tv.xml
+++ b/packages/SystemUI/res/values-cs/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Video bude připnuto v zobrazení, dokud nepřehrajete další. Funkci lze ovládat podržením tlačítka "<b>"Plocha"</b>"."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Rozumím"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Zavřít"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings_tv.xml b/packages/SystemUI/res/values-da/strings_tv.xml
index edafd7c..babb671d 100644
--- a/packages/SystemUI/res/values-da/strings_tv.xml
+++ b/packages/SystemUI/res/values-da/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Dette fastholder visningen af din video, indtil du afspiller en anden. Tryk på "<b>"START"</b>", og hold fingeren nede for at styre det."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Afvis"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings_tv.xml b/packages/SystemUI/res/values-de/strings_tv.xml
index 373d26c..1adf279 100644
--- a/packages/SystemUI/res/values-de/strings_tv.xml
+++ b/packages/SystemUI/res/values-de/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Dein Video wird dir so lange angezeigt, bis du ein anderes ansiehst. Taste "<b>"STARTBILDSCHIRM"</b>" zum Steuern drücken und halten."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Beenden"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings_tv.xml b/packages/SystemUI/res/values-el/strings_tv.xml
index 655b424..d3d2463 100644
--- a/packages/SystemUI/res/values-el/strings_tv.xml
+++ b/packages/SystemUI/res/values-el/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Αυτό διατηρεί το βίντεό σας σε προβολή έως ότου γίνει αναπαραγωγή κάποιου άλλου. Πατήστε παρατεταμένα το πλήκτρο "<b></b>" (ΑΡΧΙΚΗ ΣΕΛΙΔΑ) για να ελέγξετε αυτήν την επιλογή."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Κατάλαβα"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Παράβλεψη"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings_tv.xml b/packages/SystemUI/res/values-en-rAU/strings_tv.xml
index 730cf74..dff61c0 100644
--- a/packages/SystemUI/res/values-en-rAU/strings_tv.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"This keeps your video in view until you play another one. Press and hold "<b>"HOME"</b>" to control it."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Understood"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Dismiss"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings_tv.xml b/packages/SystemUI/res/values-en-rGB/strings_tv.xml
index 730cf74..dff61c0 100644
--- a/packages/SystemUI/res/values-en-rGB/strings_tv.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"This keeps your video in view until you play another one. Press and hold "<b>"HOME"</b>" to control it."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Understood"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Dismiss"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings_tv.xml b/packages/SystemUI/res/values-en-rIN/strings_tv.xml
index 730cf74..dff61c0 100644
--- a/packages/SystemUI/res/values-en-rIN/strings_tv.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"This keeps your video in view until you play another one. Press and hold "<b>"HOME"</b>" to control it."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Understood"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Dismiss"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings_tv.xml b/packages/SystemUI/res/values-es-rUS/strings_tv.xml
index 1dfa04c..9703b75 100644
--- a/packages/SystemUI/res/values-es-rUS/strings_tv.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Mantiene el video a la vista hasta que reproduzcas otro. Mantén presionado "<b>"INICIO"</b>" para controlar la función."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Entendido"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Descartar"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings_tv.xml b/packages/SystemUI/res/values-es/strings_tv.xml
index 32b3b8c..53e4637 100644
--- a/packages/SystemUI/res/values-es/strings_tv.xml
+++ b/packages/SystemUI/res/values-es/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"El vídeo estará visible hasta que reproduzcas otro. Mantén pulsado el botón "<b>"INICIO"</b>" para controlarlo."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Entendido"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Descartar"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings_tv.xml b/packages/SystemUI/res/values-et-rEE/strings_tv.xml
index 3386f57..1a79310 100644
--- a/packages/SystemUI/res/values-et-rEE/strings_tv.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"See hoiab teie videot kuval, kuni esitate järgmise. Selle juhtimiseks vajutage pikalt nuppu "<b>"AVAEKRAAN"</b>"."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Selge"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Loobu"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-eu-rES/strings_tv.xml b/packages/SystemUI/res/values-eu-rES/strings_tv.xml
index e1bd3a8..381e86e 100644
--- a/packages/SystemUI/res/values-eu-rES/strings_tv.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Horrela, ikusgai egongo da bideoa beste bat erreproduzitu arte. Pantaila txikia kontrolatzeko, eduki sakatuta "<b>"HOME"</b>" botoia."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Ados"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Baztertu"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings_tv.xml b/packages/SystemUI/res/values-fa/strings_tv.xml
index 86e578d..2894abba 100644
--- a/packages/SystemUI/res/values-fa/strings_tv.xml
+++ b/packages/SystemUI/res/values-fa/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"تا زمانی که ویدیوی دیگری را پخش کنید، این صفحه حالت ویدیو در ویدیوی شما را حفظ میکند. برای کنترل آن، دکمه "<b>"صفحه اصلی"</b>" را فشار دهید و نگه دارید."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"متوجه شدم"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"رد کردن"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings_tv.xml b/packages/SystemUI/res/values-fi/strings_tv.xml
index 5edd349..20c3fe4 100644
--- a/packages/SystemUI/res/values-fi/strings_tv.xml
+++ b/packages/SystemUI/res/values-fi/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Videosi pysyy näkyvissä, kunnes toistat toisen videon. Hallinnoi tilaa painamalla "<b>"HOME"</b>"-painiketta pitkään."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Selvä"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Hylkää"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings_tv.xml b/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
index 8b382a2..41a6f1b1 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Cette option maintient une vidéo affichée jusqu\'à la lecture de la suivante. Maintenez enfoncée la touche "<b>"ACCUEIL"</b>" pour la contrôler."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Fermer"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings_tv.xml b/packages/SystemUI/res/values-fr/strings_tv.xml
index db0c464..01905b8 100644
--- a/packages/SystemUI/res/values-fr/strings_tv.xml
+++ b/packages/SystemUI/res/values-fr/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Cette option maintient une vidéo affichée jusqu\'à la lecture de la suivante. Appuyez de manière prolongée sur le bouton "<b>"ACCUEIL"</b>" pour la contrôler."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Ignorer"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-gl-rES/strings_tv.xml b/packages/SystemUI/res/values-gl-rES/strings_tv.xml
index bd840aa..019f475 100644
--- a/packages/SystemUI/res/values-gl-rES/strings_tv.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"O vídeo manterase visible ata que reproduzas outro. Mantén premido "<b>"INICIO"</b>" para controlalo."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"De acordo"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Ignorar"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings_tv.xml b/packages/SystemUI/res/values-gu-rIN/strings_tv.xml
index 4af9f52..e2ce121 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings_tv.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"તમે બીજી વિડિઓ ચલાવો નહીં ત્યાં સુધી આ તમારી વિડિઓને દૃશ્યક્ષમ રાખે છે. તેને નિયંત્રિત કરવા માટે "<b>"હોમ"</b>" દબાવી અને પકડી રાખો."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"સમજાઈ ગયું"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"છોડી દો"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings_tv.xml b/packages/SystemUI/res/values-hi/strings_tv.xml
index e0b0903..8f0f898 100644
--- a/packages/SystemUI/res/values-hi/strings_tv.xml
+++ b/packages/SystemUI/res/values-hi/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"यह आपके वीडियो को तब तक दृश्यमान बनाए रखता है जब तक कि आप कोई दूसरा वीडियो नहीं चलाते. उसे नियंत्रित करने के लिए "<b>"HOME"</b>" को दबाए रखें."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"समझ लिया"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"ख़ारिज करें"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings_tv.xml b/packages/SystemUI/res/values-hr/strings_tv.xml
index e4c31c9..5d69704 100644
--- a/packages/SystemUI/res/values-hr/strings_tv.xml
+++ b/packages/SystemUI/res/values-hr/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Videozapis će se prikazivati dok ne počnete reproducirati neki drugi. Pritisnite i zadržite tipku "<b>"HOME"</b>" da biste upravljali tom značajkom."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Shvaćam"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Odbaci"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings_tv.xml b/packages/SystemUI/res/values-hu/strings_tv.xml
index db20b430..08112f5 100644
--- a/packages/SystemUI/res/values-hu/strings_tv.xml
+++ b/packages/SystemUI/res/values-hu/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"A következő lejátszásáig ezt a videót tartja előtérben. A vezérléshez tartsa nyomva a "<b>"HOME"</b>" gombot."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Rendben"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Elvetés"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings_tv.xml b/packages/SystemUI/res/values-hy-rAM/strings_tv.xml
index cd9b159..a447ba8 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings_tv.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Տեսանյութը կմնա տեսադաշտում մինչև մեկ այլ տեսանյութ նվագարկելը: Կառավարելու համար սեղմեք և պահեք "<b>"HOME"</b>" կոճակը:"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Պարզ է"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Փակել"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings_tv.xml b/packages/SystemUI/res/values-in/strings_tv.xml
index a997703..14f64b2 100644
--- a/packages/SystemUI/res/values-in/strings_tv.xml
+++ b/packages/SystemUI/res/values-in/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Tindakan ini terus menampilkan video hingga Anda memutar yang lain. Tekan dan tahan tombol "<b>"UTAMA"</b>" untuk mengontrolnya."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Mengerti"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Tutup"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-is-rIS/strings_tv.xml b/packages/SystemUI/res/values-is-rIS/strings_tv.xml
index 582c044..6e1918e 100644
--- a/packages/SystemUI/res/values-is-rIS/strings_tv.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Þetta heldur myndskeiðinu sýnilegu þar til þú spilar annað. Haltu inni "<b>"HOME"</b>" til að stjórna."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Ég skil"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Hunsa"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings_tv.xml b/packages/SystemUI/res/values-it/strings_tv.xml
index 8c47e56..7269bfa 100644
--- a/packages/SystemUI/res/values-it/strings_tv.xml
+++ b/packages/SystemUI/res/values-it/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Il video rimane visualizzato fino alla riproduzione di un altro video. Tieni premuto "<b>"HOME"</b>" per controllare la funzione."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Ignora"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings_tv.xml b/packages/SystemUI/res/values-iw/strings_tv.xml
index eea7a91..0556bb0 100644
--- a/packages/SystemUI/res/values-iw/strings_tv.xml
+++ b/packages/SystemUI/res/values-iw/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"תכונה זו שומרת על תצוגת הסרטון עד שתפעיל סרטון אחר. לחץ לחיצה ממושכת על לחצן ה"<b>"בית"</b>" כדי לשלוט בתכונה."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"הבנתי"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"דחה"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings_tv.xml b/packages/SystemUI/res/values-ja/strings_tv.xml
index 85cddf4..dce5874 100644
--- a/packages/SystemUI/res/values-ja/strings_tv.xml
+++ b/packages/SystemUI/res/values-ja/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"これにより、別のビデオを再生するまでこのビデオが表示されます。["<b>"ホーム"</b>"] を押し続けると、操作できます。"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"閉じる"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"閉じる"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings_tv.xml b/packages/SystemUI/res/values-ka-rGE/strings_tv.xml
index 67957c9..d3b5fa8 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings_tv.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"ვიდეო ჩამაგრებული იქნება, სანამ ახალს არ დაუკრავთ. სამართავად, ხანგრძლივად დააჭირეთ "<b>"მთავარ ღილაკზე"</b>"."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"გასაგებია"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"დახურვა"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings_tv.xml b/packages/SystemUI/res/values-kk-rKZ/strings_tv.xml
index c9823e9..1e0caf7 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings_tv.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Басқа бейне ойнатылғанға дейін ағымдағы бейне көрсетіле береді. Оны басқару үшін "<b>"HOME"</b>" түймесін басып тұрыңыз."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Түсіндім"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Жабу"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings_tv.xml b/packages/SystemUI/res/values-km-rKH/strings_tv.xml
index 0e7b3f2..e4d4f32 100644
--- a/packages/SystemUI/res/values-km-rKH/strings_tv.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"វាបន្តផ្អាកវីដេអូរបស់អ្នក រហូតដល់អ្នកចុចចាក់វីដេអូមួយផ្សេងទៀត។ ចុច ហើយសង្កត់ប៊ូតុង"<b>"ដើម"</b>" ដើម្បីគ្រប់គ្រងវា។"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"យល់ហើយ"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"បដិសេធ"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings_tv.xml b/packages/SystemUI/res/values-kn-rIN/strings_tv.xml
index e617c6e..5afb322 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings_tv.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"ನೀವು ಮತ್ತೊಂದನ್ನು ಪ್ಲೇ ಮಾಡುವ ತನಕ ಇದು ನಿಮ್ಮ ವೀಡಿಯೋವನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿರಿಸುತ್ತದೆ. ಅದನ್ನು ನಿಯಂತ್ರಿಸಲು "<b>"ಹೋಮ್"</b>" ಅನ್ನು ಒತ್ತಿ ಹಿಡಿಯಿರಿ."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"ಅರ್ಥವಾಯಿತು"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"ವಜಾಗೊಳಿಸಿ"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings_tv.xml b/packages/SystemUI/res/values-ko/strings_tv.xml
index b0e9f45..df22a24 100644
--- a/packages/SystemUI/res/values-ko/strings_tv.xml
+++ b/packages/SystemUI/res/values-ko/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"다른 동영상을 재생할 때까지 동영상이 계속 표시됩니다. 제어하려면 "<b>"홈"</b>"을 길게 누릅니다."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"확인"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"닫기"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings_tv.xml b/packages/SystemUI/res/values-ky-rKG/strings_tv.xml
index 771e395..3d34e2f 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings_tv.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Ушуну менен, башка видео ойнотмоюнча видеоңуз көрсөтүлө берет. Аны башкаруу үчүн "<b>"БАШКЫ БЕТ"</b>" баскычын басып, кармап туруңуз."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Түшүндүм"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Көз жаздымда калтыруу"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings_tv.xml b/packages/SystemUI/res/values-lo-rLA/strings_tv.xml
index ba32597..cf2ef1e 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings_tv.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"ນີ້ຈະເປັນການເຮັດໃຫ້ວິດີໂອຂອງທ່ານຢູ່ໃນມຸມມອງຈົນກວ່າທ່ານຈະຫຼິ້ນວິດີໂອອື່ນ. ໃຫ້ກົດປຸ່ມ "<b>"HOME"</b>" ຄ້າງໄວ້ເພື່ອຄວບຄຸມມັນ."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"ເຂົ້າໃຈແລ້ວ"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"ປິດໄວ້"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings_tv.xml b/packages/SystemUI/res/values-lt/strings_tv.xml
index e263da4..0cdc085 100644
--- a/packages/SystemUI/res/values-lt/strings_tv.xml
+++ b/packages/SystemUI/res/values-lt/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Vaizdo įrašas bus rodomas, kol paleisite kitą vaizdo įrašą. Jei norite valdyti, palaikykite paspaudę mygtuką "<b>"HOME"</b>"."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Supratau"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Atsisakyti"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings_tv.xml b/packages/SystemUI/res/values-lv/strings_tv.xml
index cafc10d..33450fa 100644
--- a/packages/SystemUI/res/values-lv/strings_tv.xml
+++ b/packages/SystemUI/res/values-lv/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Šādi videoklips būs redzams, līdz atskaņosiet citu videoklipu. Lai to kontrolētu, nospiediet un turiet nospiestu pogu "<b>"HOME"</b>"."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Labi"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Nerādīt"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings_tv.xml b/packages/SystemUI/res/values-mk-rMK/strings_tv.xml
index 453272c..6d7a53a 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings_tv.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Видеото се прикажува сѐ додека не пуштите друго. Притиснете и задржете "<b>"ПОЧЕТЕН ЕКРАН"</b>" за да го контролирате."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Разбрав"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Отфрли"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings_tv.xml b/packages/SystemUI/res/values-ml-rIN/strings_tv.xml
index 48bdb51..e971b9a 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings_tv.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"മറ്റൊരു വീഡിയോ പ്ലേ ചെയ്യുന്നത് വരെ നിങ്ങളുടെ വീഡിയോയെ ഇത് കാഴ്ചയിൽ നിലനിർത്തുന്നു. ഇത് നിയന്ത്രിക്കുന്നതിന് "<b>"ഹോം"</b>" അമർത്തിപ്പിടിക്കുക."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"മനസ്സിലായി"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"ഡിസ്മിസ് ചെയ്യുക"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings_tv.xml b/packages/SystemUI/res/values-mn-rMN/strings_tv.xml
index 8c6ffbb..40933d8 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings_tv.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Таныг өөр видео тоглуулах хүртэл таны видеог гаргасаар байх болно. Үүнийг удирдахын тулд "<b>"НҮҮР ХУУДАС"</b>" товчлуурыг дараад, хүлээнэ үү."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Ойлголоо"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Хаах"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings_tv.xml b/packages/SystemUI/res/values-mr-rIN/strings_tv.xml
index 58415000..bfada64 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings_tv.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"आपण दुसरा व्हिडिओ प्ले करेपर्यंत हे आपल्या व्हिडिओस दृश्यामध्ये ठेवते. ते नियंत्रित करण्यासाठी "<b>"मुख्यपृष्ठ"</b>" दाबा आणि धरून ठेवा."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"समजले"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"डिसमिस करा"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings_tv.xml b/packages/SystemUI/res/values-ms-rMY/strings_tv.xml
index 502f231..de221cc 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings_tv.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Tindakan ini memastikan video anda sentiasa dipaparkan sehingga anda memainkan video lain. Tekan dan tahan "<b>"SKRIN UTAMA"</b>" untuk mengawalnya."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Ketepikan"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-my-rMM/strings_tv.xml b/packages/SystemUI/res/values-my-rMM/strings_tv.xml
index 4ce1992..2c5b94b 100644
--- a/packages/SystemUI/res/values-my-rMM/strings_tv.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"နောက်တစ်ခုမဖွင့်မချင်း သင့်ဗီဒီယိုကို ပြသထားပါမည်။ ၎င်းကိုထိန်းချုပ်ရန် "<b>"ပင်မ"</b>" ခလုတ်ကို နှိပ်ပြီးဖိထားပါ။"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"ရပါပြီ"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"ပယ်ပါ"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings_tv.xml b/packages/SystemUI/res/values-nb/strings_tv.xml
index 3dc7ae0..20b0f24 100644
--- a/packages/SystemUI/res/values-nb/strings_tv.xml
+++ b/packages/SystemUI/res/values-nb/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Dette holder videoen din synlig frem til du spiller av en annen video. Trykk og hold inne "<b>"HOME"</b>" for å styre dette."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Greit"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Avvis"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings_tv.xml b/packages/SystemUI/res/values-ne-rNP/strings_tv.xml
index 61a1669..648eed0 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings_tv.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"तपाईँले अर्को भिडियोलाई प्ले नगरेसम्म यसले तपाईँको भिडियोलाई दृश्यमा राख्दछ। यसलाई नियन्त्रण गर्नका लागि "<b>"HOME"</b>" लाई थिचिरहनुहोस्।"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"बुझेँ"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"खारेज गर्नुहोस्"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings_tv.xml b/packages/SystemUI/res/values-nl/strings_tv.xml
index ee0510c..4fdaf5d 100644
--- a/packages/SystemUI/res/values-nl/strings_tv.xml
+++ b/packages/SystemUI/res/values-nl/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Hiermee blijft je video in beeld totdat je een andere afspeelt. Houd "<b>"HOME"</b>" ingedrukt om de functie te bedienen."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Sluiten"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings_tv.xml b/packages/SystemUI/res/values-pa-rIN/strings_tv.xml
index afaa658..cbd5cbf 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings_tv.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"ਇਹ ਤੁਹਾਡੀ ਵੀਡੀਓ ਨੂੰ ਤਦ ਤੱਕ ਦ੍ਰਿਸ਼ ਵਿੱਚ ਰੱਖਦਾ ਹੈ, ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਕੋਈ ਹੋਰ ਵੀਡੀਓ ਨਹੀਂ ਚਲਾਉਂਦੇ ਹੋ। ਇਸ ਨੂੰ ਕੰਟਰੋਲ ਕਰਨ ਲਈ "<b>"ਹੋਮ"</b>" ਬਟਨ ਨੂੰ ਦੱਬੋ ਅਤੇ ਦਬਾਈ ਰੱਖੋ।"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"ਸਮਝ ਲਿਆ"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"ਖ਼ਾਰਜ ਕਰੋ"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings_tv.xml b/packages/SystemUI/res/values-pl/strings_tv.xml
index 03a18bd..09c63e4 100644
--- a/packages/SystemUI/res/values-pl/strings_tv.xml
+++ b/packages/SystemUI/res/values-pl/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"W tym trybie film pozostaje na ekranie do czasu, aż odtworzysz kolejny. Aby sterować trybem, przytrzymaj przycisk "<b>"EKRAN GŁÓWNY"</b>"."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Zamknij"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings_tv.xml b/packages/SystemUI/res/values-pt-rBR/strings_tv.xml
index 1857fee..4b76e64 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings_tv.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Esse recurso faz com que seu vídeo continue sendo exibido até que você reproduza outro. Mantenha "<b>"INÍCIO"</b>" pressionado para controlá-lo."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Entendi"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Dispensar"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings_tv.xml b/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
index 915b227..9465cc2 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Esta opção mantém o vídeo visível até reproduzir outro vídeo. Prima sem soltar "<b>"HOME"</b>" para o controlar."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Compreendi"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Ignorar"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings_tv.xml b/packages/SystemUI/res/values-pt/strings_tv.xml
index 1857fee..4b76e64 100644
--- a/packages/SystemUI/res/values-pt/strings_tv.xml
+++ b/packages/SystemUI/res/values-pt/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Esse recurso faz com que seu vídeo continue sendo exibido até que você reproduza outro. Mantenha "<b>"INÍCIO"</b>" pressionado para controlá-lo."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Entendi"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Dispensar"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 5f3eed7..8c72f6a 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -71,7 +71,7 @@
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Se salv. captura de ecran..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Se salvează captura de ecran..."</string>
<string name="screenshot_saving_text" msgid="2419718443411738818">"Captura de ecran este salvată."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Captură de ecran realizată."</string>
+ <string name="screenshot_saved_title" msgid="6461865960961414961">"Captură de ecran salvată."</string>
<string name="screenshot_saved_text" msgid="2685605830386712477">"Atingeți pentru a vedea captura de ecran."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Captura de ecran nu a putut fi realizată."</string>
<string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Problemă întâmpinată la salvarea capturii de ecran."</string>
diff --git a/packages/SystemUI/res/values-ro/strings_tv.xml b/packages/SystemUI/res/values-ro/strings_tv.xml
index 0287cb7..233eb3a 100644
--- a/packages/SystemUI/res/values-ro/strings_tv.xml
+++ b/packages/SystemUI/res/values-ro/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Astfel, videoclipul este afișat până când redați alt videoclip. Apăsați lung pe butonul "<b>"ACASĂ"</b>" pentru a controla funcția."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Am înțeles"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Închideți"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings_tv.xml b/packages/SystemUI/res/values-ru/strings_tv.xml
index 3c00160..d60a114 100644
--- a/packages/SystemUI/res/values-ru/strings_tv.xml
+++ b/packages/SystemUI/res/values-ru/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Позволяет смотреть одно видео в другом. Для управления нажмите и удерживайте клавишу "<b>"HOME"</b>"."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"ОК"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Закрыть"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-si-rLK/strings_tv.xml b/packages/SystemUI/res/values-si-rLK/strings_tv.xml
index 7c3d4fc..7fd7641 100644
--- a/packages/SystemUI/res/values-si-rLK/strings_tv.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"මෙය ඔබේ වීඩියෝව ඔබ වෙනත් එකක් ධාවනය කරන තෙක් දසුනෙහි තබා ගනියි. එය පාලනය කිරීමට "<b>"මුල් පිටුව"</b>" ඔබා අල්ලාගෙන සිටින්න."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"හරි, තේරුණා"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"අස් කරන්න"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings_tv.xml b/packages/SystemUI/res/values-sk/strings_tv.xml
index f4e781a..2972862 100644
--- a/packages/SystemUI/res/values-sk/strings_tv.xml
+++ b/packages/SystemUI/res/values-sk/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Táto možnosť podrží video v obraze, dokým prehráte ďalšie. Stlačením a podržaním tlačidla "<b>"HOME"</b>" ho môžete ovládať."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Dobre"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Odmietnuť"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings_tv.xml b/packages/SystemUI/res/values-sl/strings_tv.xml
index b29253f..72f3c0c 100644
--- a/packages/SystemUI/res/values-sl/strings_tv.xml
+++ b/packages/SystemUI/res/values-sl/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"S tem videoposnetek ostane v pogledu, dokler ne predvajate drugega. Pridržite tipko "<b>"HOME"</b>", če ga želite upravljati."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Razumem"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Opusti"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings_tv.xml b/packages/SystemUI/res/values-sq-rAL/strings_tv.xml
index 4d9ed2b..9bfd18f 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings_tv.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Kjo e mban videon të dukshme derisa të luash një tjetër. Shtyp dhe mbaj shtypur "<b>"HOME"</b>" për ta kontrolluar."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"E kuptova"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Hiqe"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings_tv.xml b/packages/SystemUI/res/values-sr/strings_tv.xml
index f5d948d..85a21a9 100644
--- a/packages/SystemUI/res/values-sr/strings_tv.xml
+++ b/packages/SystemUI/res/values-sr/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"На овај начин ће видео бити приказан док не пустите неки други. Притисните и задржите "<b>"ПОЧЕТНА"</b>" да бисте га контролисали."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Важи"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Одбаци"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings_tv.xml b/packages/SystemUI/res/values-sv/strings_tv.xml
index 6341d5f..4e1281b 100644
--- a/packages/SystemUI/res/values-sv/strings_tv.xml
+++ b/packages/SystemUI/res/values-sv/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Då visas videon tills du spelar upp en annan. Tryck länge på "<b>"startknappen"</b>" om du vill styra uppspelningen."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Ignorera"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings_tv.xml b/packages/SystemUI/res/values-sw/strings_tv.xml
index 20e96293..02c28ae 100644
--- a/packages/SystemUI/res/values-sw/strings_tv.xml
+++ b/packages/SystemUI/res/values-sw/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Hali hii itaendelea kuonyesha video yako hadi utakapocheza video nyingine. Bonyeza na ushikilie kitufe cha "<b>"HOME"</b>" ili uidhibiti."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Nimeelewa"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Ondoa"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings_tv.xml b/packages/SystemUI/res/values-ta-rIN/strings_tv.xml
index f875a37..cf9a500 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings_tv.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"இது நீங்கள் அடுத்த வீடியோவை இயக்கும் வரை தற்போதுள்ள வீடியோவை வைத்திருக்கும். அதைக் கட்டுப்படுத்த, "<b>"முகப்பு"</b>" என்பதை அழுத்திப் பிடிக்கவும்."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"சரி"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"நிராகரி"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-te-rIN/strings_tv.xml b/packages/SystemUI/res/values-te-rIN/strings_tv.xml
index c48b6b9..d065cbd 100644
--- a/packages/SystemUI/res/values-te-rIN/strings_tv.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"ఇది మీరు మరొకటి ప్లే చేసే వరకు మీ వీడియోను వీక్షణలో ఉంచుతుంది. దాన్ని నియంత్రించడానికి "<b>"హోమ్"</b>" నొక్కి, పట్టుకోండి."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"అర్థమైంది"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"తీసివేస్తుంది"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings_tv.xml b/packages/SystemUI/res/values-th/strings_tv.xml
index 7ac4807..b6c61f1 100644
--- a/packages/SystemUI/res/values-th/strings_tv.xml
+++ b/packages/SystemUI/res/values-th/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"การตั้งค่านี้จะทำให้คุณมองเห็นวิดีโอนี้จนกว่าคุณจะเล่นวิดีโออีกรายการหนึ่ง กดปุ่ม"<b>"หน้าแรก"</b>"ค้างไว้เพื่อควบคุม"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"รับทราบ"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"ปิด"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings_tv.xml b/packages/SystemUI/res/values-tl/strings_tv.xml
index 45fa081..83244de 100644
--- a/packages/SystemUI/res/values-tl/strings_tv.xml
+++ b/packages/SystemUI/res/values-tl/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Pinapanatili nitong nakikita ang iyong video hanggang sa mag-play ka ng iba. Pindutin nang matagal ang "<b>"HOME"</b>" upang kontrolin ito."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"I-dismiss"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings_tv.xml b/packages/SystemUI/res/values-tr/strings_tv.xml
index 8fe5395..bcce465 100644
--- a/packages/SystemUI/res/values-tr/strings_tv.xml
+++ b/packages/SystemUI/res/values-tr/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Bu işlev, videonuzu, başka bir video oynatılıncaya kadar görünür tutar. Bu işlevi kontrol etmek için "<b>"ANA EKRAN"</b>" tuşunu basılı tutun."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Anladım"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Kapat"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings_tv.xml b/packages/SystemUI/res/values-uk/strings_tv.xml
index 76277d6..0d5750a 100644
--- a/packages/SystemUI/res/values-uk/strings_tv.xml
+++ b/packages/SystemUI/res/values-uk/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Відео буде закріплено, доки ви не запустите інше відео. Щоб керувати, утримуйте кнопку "<b>"HOME"</b>"."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Закрити"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings_tv.xml b/packages/SystemUI/res/values-ur-rPK/strings_tv.xml
index 1844c96..b5b0b72 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings_tv.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"یہ آپ کی ویڈیو تب تک دکھاتا رہتا ہے جب تک آپ کوئی دوسری نہیں چلاتے۔ اسے کنٹرول کرنے کیلئے "<b>"ہوم"</b>" دبائیں اور پکڑے رہیں۔"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"سمجھ آ گئی"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"برخاست کریں"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings_tv.xml b/packages/SystemUI/res/values-uz-rUZ/strings_tv.xml
index 2af885e..a9cbac48 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings_tv.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Bir videoni boshqasida ko‘rish imkonini beradi. Boshqarish uchun "<b>"HOME"</b>" tugmasini bosib turing."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Yopish"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings_tv.xml b/packages/SystemUI/res/values-vi/strings_tv.xml
index 21343be..30b1e88 100644
--- a/packages/SystemUI/res/values-vi/strings_tv.xml
+++ b/packages/SystemUI/res/values-vi/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Màn hình này sẽ giữ video của bạn ở chế độ xem cho đến khi bạn phát video khác. Nhấn và giữ "<b>"HOME"</b>" để điều khiển màn hình."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Loại bỏ"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings_tv.xml b/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
index e29dec3..db9b2c8 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"这样会固定显示您的视频,直到您播放其他视频为止。按住"<b>"主屏幕"</b>"按钮即可控制该功能。"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"知道了"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"关闭"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings_tv.xml b/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
index bc164c8..deba65b 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"這讓您繼續觀看影片,直至您播放下一部影片。按住"<b>"主按鈕"</b>"即可控制「畫中畫」。"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"知道了"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"關閉"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings_tv.xml b/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
index 583a6ed..890995c 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"您的影片會一直顯示在畫面中,直到您播放其他影片為止。按住 [HOME] (主畫面) 按鈕即可控制子母畫面。"<b></b></string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"我知道了"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"關閉"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings_tv.xml b/packages/SystemUI/res/values-zu/strings_tv.xml
index e1d0b5b..71c2e0936 100644
--- a/packages/SystemUI/res/values-zu/strings_tv.xml
+++ b/packages/SystemUI/res/values-zu/strings_tv.xml
@@ -28,4 +28,6 @@
<string name="pip_onboarding_description" msgid="4028124563309465267">"Lokhu kugcina ividiyo yakho ibonakala uze udlale enye. Cindezela futhi ubambe okuthi "<b>"EKHAYA"</b>" ukuze uyilawule."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Ngiyezwa"</string>
<string name="recents_tv_dismiss" msgid="3555093879593377731">"Cashisa"</string>
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index cb51649..d12ef42 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -30,9 +30,6 @@
<color name="batterymeter_charge_color">#FFFFFFFF</color>
<color name="batterymeter_bolt_color">#FFFFFFFF</color>
<color name="qs_batterymeter_frame_color">#FF404040</color>
- <color name="system_primary_color">#ff263238</color><!-- blue grey 900 -->
- <color name="system_secondary_color">#ff37474F</color><!-- blue grey 800 -->
- <color name="system_accent_color">#ff80CBC4</color><!-- deep teal 200 -->
<color name="system_warning_color">#fff4511e</color><!-- deep orange 600 -->
<color name="qs_text">#FFFFFFFF</color>
<color name="qs_tile_divider">#29ffffff</color><!-- 16% white -->
@@ -41,7 +38,6 @@
<color name="qs_detail_button">#FFB0BEC5</color><!-- 100% blue grey 200 -->
<color name="qs_detail_button_white">#B3FFFFFF</color><!-- 70% white -->
<color name="qs_detail_transition">#66FFFFFF</color>
- <color name="qs_detail_progress_track">#99009688</color><!-- 60% deep teal 500 -->
<color name="data_usage_secondary">#99FFFFFF</color><!-- 60% white -->
<color name="data_usage_graph_track">#33FFFFFF</color><!-- 20% white -->
<color name="data_usage_graph_warning">#FFFFFFFF</color>
@@ -99,15 +95,11 @@
<!-- The color of the ripples on the tinted notifications -->
<color name="notification_ripple_tinted_color">#30ffffff</color>
- <!-- The color of the circle around the primary user in the user switcher -->
- <color name="current_user_border_color">@color/system_accent_color</color>
-
<!-- The color of the gear shown behind a notification -->
<color name="notification_gear_color">#ff757575</color>
<!-- The "inside" of a notification, reached via longpress -->
<color name="notification_guts_bg_color">#eeeeee</color>
- <color name="notification_guts_slider_color">@*android:color/material_deep_teal_500</color>
<color name="notification_guts_disabled_slider_color">@*android:color/material_grey_300</color>
<color name="notification_guts_secondary_slider_color">#858383</color>
<color name="notification_guts_icon_tint">#8a000000</color>
@@ -126,8 +118,6 @@
<!-- Shadow color for the furthest pixels around the fake shadow for recents. -->
<color name="fake_shadow_end_color">#03000000</color>
- <color name="screen_pinning_nav_icon_highlight_outer">#4080cbc4</color><!-- 25% deep teal 200 -->
- <color name="screen_pinning_request_bg">#ff009688</color><!-- deep teal 500 -->
<color name="screen_pinning_request_window_bg">#80000000</color>
<color name="segmented_buttons_background">#14FFFFFF</color><!-- 8% white -->
@@ -142,14 +132,10 @@
<color name="light_mode_icon_color_dual_tone_background">#4dffffff</color>
<color name="light_mode_icon_color_dual_tone_fill">#ffffff</color>
- <color name="zen_introduction_message_background">#ff009688</color><!-- deep teal 500 -->
<color name="volume_icon_color">#ffffffff</color>
<color name="volume_settings_icon_color">#7fffffff</color>
<color name="volume_slider_inactive">#FFB0BEC5</color><!-- blue grey 200 -->
- <color name="fab_ripple">#1fffffff</color><!-- 12% white -->
- <color name="fab_shape">#ff009688</color><!-- Teal 500 -->
-
<color name="docked_divider_background">#ff000000</color>
<color name="docked_divider_handle">#ffffff</color>
<drawable name="forced_resizable_background">#59000000</drawable>
@@ -166,16 +152,10 @@
<color name="qs_tile_tint_inactive">#4dffffff</color>
<color name="qs_tile_tint_active">#ffffffff</color>
- <color name="switch_bar_background">#ff37474f</color>
- <color name="switch_accent_color">#ff7fcac3</color>
-
<!-- Keyboard shortcuts colors -->
- <color name="ksh_system_group_color">@color/material_deep_teal_500</color>
<color name="ksh_application_group_color">#fff44336</color>
<color name="ksh_keyword_color">#d9000000</color>
<color name="ksh_key_item_color">@color/material_grey_600</color>
<color name="ksh_key_item_background">@color/material_grey_100</color>
- <!-- Background color of edit overflow -->
- <color name="qs_edit_overflow_bg">#455A64</color>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index eef5717..0365e80 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -535,6 +535,19 @@
<!-- Volume dialog root view bottom margin, at rest -->
<dimen name="volume_dialog_margin_bottom">4dp</dimen>
+ <dimen name="volume_dialog_collapsed_padding_top">8dp</dimen>
+ <dimen name="volume_dialog_expanded_padding_top">22dp</dimen>
+ <dimen name="volume_dialog_padding_end">40dp</dimen>
+
+ <dimen name="volume_row_padding_bottom">9.4dp</dimen>
+ <dimen name="volume_row_padding_start">4dp</dimen>
+ <dimen name="volume_row_header_padding_start">16dp</dimen>
+ <dimen name="volume_row_height">64dp</dimen>
+ <dimen name="volume_row_slider_height">48dp</dimen>
+ <dimen name="volume_row_slider_padding_start">12dp</dimen>
+
+ <dimen name="volume_expander_margin_end">2dp</dimen>
+ <dimen name="volume_expander_margin_top">6dp</dimen>
<!-- Padding between icon and text for managed profile toast -->
<dimen name="managed_profile_toast_padding">4dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index f7a169c..4f523f3 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -348,6 +348,9 @@
<!-- Content description of the data connection type 4G for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_data_connection_4g">4G</string>
+ <!-- Content description of the data connection type 4G for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_data_connection_4g_plus">4G+</string>
+
<!-- Content description of the data connection type LTE for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_data_connection_lte">LTE</string>
@@ -1093,14 +1096,14 @@
<!-- Toast shown when user unlocks screen and managed profile activity is in the foreground -->
<string name="managed_profile_foreground_toast">You\'re using your work profile</string>
- <string-array name="volume_stream_titles" translatable="false">
- <item>Voice calls</item> <!-- STREAM_VOICE_CALL -->
+ <string-array name="volume_stream_titles">
+ <item>Call</item> <!-- STREAM_VOICE_CALL -->
<item>System</item> <!-- STREAM_SYSTEM -->
- <item>Notifications</item> <!-- STREAM_RING -->
+ <item>Ring</item> <!-- STREAM_RING -->
<item>Media</item> <!-- STREAM_MUSIC -->
- <item>Alarms</item> <!-- STREAM_ALARM -->
+ <item>Alarm</item> <!-- STREAM_ALARM -->
<item></item> <!-- STREAM_NOTIFICATION -->
- <item>Bluetooth calls</item> <!-- STREAM_BLUETOOTH_SCO -->
+ <item>Bluetooth</item> <!-- STREAM_BLUETOOTH_SCO -->
<item></item> <!-- STREAM_SYSTEM_ENFORCED -->
<item></item> <!-- STREAM_DTMF -->
<item></item> <!-- STREAM_TTS -->
diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml
index b1d23d8..f49d201 100644
--- a/packages/SystemUI/res/values/strings_tv.xml
+++ b/packages/SystemUI/res/values/strings_tv.xml
@@ -44,4 +44,8 @@
<string name="font_roboto_regular" translatable="false">sans-serif</string>
<!-- DO NOT TRANSLATE -->
<string name="font_roboto_light" translatable="false">sans-serif-light</string>
+ <!-- Package names to be blacklisted in Recents, add package names into overlay as needed -->
+ <string-array name="recents_tv_blacklist_array">
+ </string-array>
+
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index aeb484f..e5681ce 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -132,7 +132,7 @@
<style name="TextAppearance.QS.DetailItemSecondary">
<item name="android:textSize">@dimen/qs_detail_item_secondary_text_size</item>
- <item name="android:textColor">@color/system_accent_color</item>
+ <item name="android:textColor">?android:attr/colorAccent</item>
</style>
<style name="TextAppearance.QS.Introduction">
@@ -177,7 +177,7 @@
<style name="TextAppearance.QS.DataUsage.Usage">
<item name="android:textSize">@dimen/qs_data_usage_usage_text_size</item>
- <item name="android:textColor">@color/system_accent_color</item>
+ <item name="android:textColor">?android:attr/colorAccent</item>
</style>
<style name="TextAppearance.QS.DataUsage.Secondary">
@@ -217,19 +217,13 @@
<style name="Animation.StatusBar">
</style>
- <style name="systemui_theme" parent="@android:style/Theme.DeviceDefault">
- <item name="android:colorPrimary">@color/system_primary_color</item>
- <item name="android:colorControlActivated">@color/system_accent_color</item>
- </style>
+ <style name="systemui_theme" parent="@android:style/Theme.DeviceDefault" />
<style name="systemui_theme_remote_input" parent="@android:style/Theme.DeviceDefault.Light">
<item name="android:colorAccent">@color/remote_input_accent</item>
</style>
- <style name="Theme.SystemUI.Dialog" parent="@android:style/Theme.DeviceDefault.Light.Dialog">
- <item name="android:colorPrimary">@color/system_primary_color</item>
- <item name="android:colorControlActivated">@color/system_accent_color</item>
- </style>
+ <style name="Theme.SystemUI.Dialog" parent="@android:style/Theme.DeviceDefault.Light.Dialog" />
<style name="Theme.SystemUI.Dialog.Alert" parent="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert" />
@@ -320,12 +314,12 @@
<item name="android:layout_height">48dp</item>
</style>
- <style name="TunerSettings" parent="@android:style/Theme.Material.Settings">
+ <style name="TunerSettings" parent="@android:style/Theme.DeviceDefault.Settings">
<item name="android:windowActionBar">false</item>
<item name="preferenceTheme">@style/TunerPreferenceTheme</item>
</style>
- <style name="TunerPreferenceTheme" parent="@android:style/Theme.Material.Settings">
+ <style name="TunerPreferenceTheme" parent="@android:style/Theme.DeviceDefault.Settings">
<item name="dropdownPreferenceStyle">@style/Preference.DropDown.Material</item>
</style>
@@ -341,16 +335,16 @@
</style>
<style name="TextAppearance.NotificationGuts.Secondary">
- <item name="android:alpha">.54</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
</style>
<style name="TextAppearance.NotificationGuts.Primary">
- <item name="android:alpha">.87</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:textSize">16sp</item>
</style>
<style name="TextAppearance.NotificationGuts.Radio">
- <item name="android:alpha">.87</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
<style name="TextAppearance.NotificationGuts.Button">
@@ -358,15 +352,11 @@
<item name="android:textAllCaps">true</item>
<item name="android:fontFamily">sans-serif-medium</item>
<item name="android:gravity">center</item>
- <item name="android:textColor">@*android:color/material_deep_teal_500</item>
+ <item name="android:textColor">?android:attr/colorAccent</item>
</style>
- <style name="ThemeOverlay.SwitchBar" parent="@android:style/ThemeOverlay">
- <item name="android:colorAccent">@color/switch_accent_color</item>
- </style>
-
- <style name="edit_theme" parent="@android:style/Theme.Material">
- <item name="android:colorBackground">@color/qs_edit_overflow_bg</item>
+ <style name="edit_theme" parent="@*android:style/Theme.DeviceDefault.Settings.Dark">
+ <item name="android:colorBackground">?android:attr/colorSecondary</item>
</style>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUI.java b/packages/SystemUI/src/com/android/systemui/SystemUI.java
index 85befff..f30baee 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUI.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUI.java
@@ -16,8 +16,10 @@
package com.android.systemui;
+import android.app.Notification;
import android.content.Context;
import android.content.res.Configuration;
+import android.os.Bundle;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -48,4 +50,12 @@
mComponents.put(interfaceType, component);
}
}
+
+ public static void overrideNotificationAppName(Context context, Notification.Builder n) {
+ final Bundle extras = new Bundle();
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
+ context.getString(com.android.internal.R.string.android_system_label));
+
+ n.addExtras(extras);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 3bbcf6e..42a9ed5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -926,6 +926,11 @@
// In this case, send out ACTION_USER_PRESENT here instead of in
// handleKeyguardDone()
sendUserPresentBroadcast();
+ } else if (mSystemReady && shouldWaitForProvisioning()) {
+ // Skipping the lockscreen because we're not yet provisioned, but we still need to
+ // notify the StrongAuthTracker that it's now safe to run trust agents, in case the
+ // user sets a credential later.
+ getLockPatternUtils().userPresent(KeyguardUpdateMonitor.getCurrentUser());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index ea1c9bf..b831235 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -38,6 +38,7 @@
import android.util.Slog;
import com.android.systemui.R;
+import com.android.systemui.SystemUI;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.phone.SystemUIDialog;
@@ -143,6 +144,7 @@
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setColor(mContext.getColor(
com.android.internal.R.color.system_notification_accent_color));
+ SystemUI.overrideNotificationAppName(mContext, nb);
final Notification n = nb.build();
mNoMan.notifyAsUser(TAG_NOTIFICATION, R.id.notification_power, n, UserHandle.ALL);
}
@@ -173,8 +175,8 @@
attachLowBatterySound(nb);
mPlaySound = false;
}
- final Notification n = nb.build();
- mNoMan.notifyAsUser(TAG_NOTIFICATION, R.id.notification_power, n, UserHandle.ALL);
+ SystemUI.overrideNotificationAppName(mContext, nb);
+ mNoMan.notifyAsUser(TAG_NOTIFICATION, R.id.notification_power, nb.build(), UserHandle.ALL);
}
private PendingIntent pendingActivity(Intent intent) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/DataUsageGraph.java b/packages/SystemUI/src/com/android/systemui/qs/DataUsageGraph.java
index aff5d2b..5f23a40 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/DataUsageGraph.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/DataUsageGraph.java
@@ -24,6 +24,7 @@
import android.util.AttributeSet;
import android.view.View;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
public class DataUsageGraph extends View {
@@ -45,7 +46,7 @@
super(context, attrs);
final Resources res = context.getResources();
mTrackColor = context.getColor(R.color.data_usage_graph_track);
- mUsageColor = context.getColor(R.color.system_accent_color);
+ mUsageColor = Utils.getColorAccent(context);
mOverlimitColor = context.getColor(R.color.system_warning_color);
mWarningColor = context.getColor(R.color.data_usage_graph_warning);
mMarkerWidth = res.getDimensionPixelSize(R.dimen.data_usage_graph_marker_width);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 109d2c2..ce6aa71 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -72,6 +72,8 @@
private QSCustomizer mCustomizePanel;
private Record mDetailRecord;
+ private BrightnessMirrorController mBrightnessMirrorController;
+
public QSPanel(Context context) {
this(context, null);
}
@@ -157,7 +159,7 @@
}
public void setBrightnessMirror(BrightnessMirrorController c) {
- super.onFinishInflate();
+ mBrightnessMirrorController = c;
ToggleSlider brightnessSlider = (ToggleSlider) findViewById(R.id.brightness_slider);
ToggleSlider mirror = (ToggleSlider) c.getMirror().findViewById(R.id.brightness_slider);
brightnessSlider.setMirror(mirror);
@@ -203,6 +205,11 @@
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mFooter.onConfigurationChanged();
+
+ if (mBrightnessMirrorController != null) {
+ // Reload the mirror in case it got reinflated but we didn't.
+ setBrightnessMirror(mBrightnessMirrorController);
+ }
}
public void onCollapse() {
@@ -351,7 +358,6 @@
}
};
r.tileView.init(click, longClick);
- callback.onStateChanged(r.tile.getState());
r.tile.refreshState();
mRecords.add(r);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 974de08..27b079a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -225,7 +225,7 @@
private void handleAddCallback(Callback callback) {
mCallbacks.add(callback);
- handleRefreshState(null);
+ callback.onStateChanged(mState);
}
private void handleRemoveCallback(Callback callback) {
@@ -634,6 +634,18 @@
}
}
+ public static class AirplaneBooleanState extends BooleanState {
+ public boolean isAirplaneMode;
+
+ @Override
+ public boolean copyTo(State other) {
+ final AirplaneBooleanState o = (AirplaneBooleanState) other;
+ final boolean changed = super.copyTo(other) || o.isAirplaneMode != isAirplaneMode;
+ o.isAirplaneMode = isAirplaneMode;
+ return changed;
+ }
+ }
+
public static final class SignalState extends BooleanState {
public boolean connected;
public boolean activityIn;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index afc987e2..f09275d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -113,6 +113,11 @@
}
@Override
+ protected void onTileClick(QSTile<?> tile) {
+ tile.secondaryClick();
+ }
+
+ @Override
public void onTuningChanged(String key, String newValue) {
// No tunings for you.
if (key.equals(QS_SHOW_BRIGHTNESS)) {
@@ -130,7 +135,7 @@
break;
}
}
- super.setTiles(quickTiles, false);
+ super.setTiles(quickTiles, true);
}
private final Tunable mNumTiles = new Tunable() {
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 8a0079d..0de1e30 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -233,6 +233,7 @@
setVisibility(View.GONE);
}
mNotifQsContainer.setCustomizerAnimating(false);
+ mRecyclerView.setAdapter(mTileAdapter);
}
@Override
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 60c24d0..3a693cf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -19,6 +19,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.ColorDrawable;
import android.os.Handler;
@@ -37,6 +38,7 @@
import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;
import android.widget.TextView;
+
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto;
import com.android.systemui.R;
@@ -70,6 +72,7 @@
private final Handler mHandler = new Handler();
private final List<TileInfo> mTiles = new ArrayList<>();
private final ItemTouchHelper mItemTouchHelper;
+ private final ItemDecoration mDecoration;
private final AccessibilityManager mAccessibilityManager;
private int mEditIndex;
private int mTileDividerIndex;
@@ -87,6 +90,7 @@
mContext = context;
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
mItemTouchHelper = new ItemTouchHelper(mCallbacks);
+ mDecoration = new TileItemDecoration(context);
}
public void setHost(QSTileHost host) {
@@ -111,6 +115,9 @@
}
public void setTileSpecs(List<String> currentSpecs) {
+ if (currentSpecs.equals(mCurrentSpecs)) {
+ return;
+ }
mCurrentSpecs = currentSpecs;
recalcSpecs();
}
@@ -227,6 +234,8 @@
});
if (mNeedsFocus) {
// Wait for this to get laid out then set its focus.
+ // Ensure that tile gets laid out so we get the callback.
+ holder.mTileView.requestLayout();
holder.mTileView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom,
@@ -254,7 +263,7 @@
}
holder.mTileView.onStateChanged(info.state);
holder.mTileView.setAppLabel(info.appLabel);
- holder.mTileView.setShowAppLabel(mTileDividerIndex > -1 && position > mTileDividerIndex);
+ holder.mTileView.setShowAppLabel(position > mEditIndex && !info.isSystem);
if (mAccessibilityManager.isTouchExplorationEnabled()) {
final boolean selectable = !mAccessibilityMoving || position < mEditIndex;
@@ -289,13 +298,11 @@
mTiles.remove(mEditIndex--);
notifyItemRemoved(mEditIndex - 1);
move(mAccessibilityFromIndex, position, v);
- updateDividerLocations();
notifyDataSetChanged();
- saveSpecs(mHost);
}
private void showAccessibilityDialog(final int position, final View v) {
- TileInfo info = mTiles.get(position);
+ final TileInfo info = mTiles.get(position);
CharSequence[] options = new CharSequence[] {
mContext.getString(R.string.accessibility_qs_edit_move_tile, info.state.label),
mContext.getString(R.string.accessibility_qs_edit_remove_tile, info.state.label),
@@ -307,7 +314,9 @@
if (which == 0) {
startAccessibleDrag(position);
} else {
- move(position, mEditIndex, v);
+ move(position, info.isSystem ? mEditIndex : mTileDividerIndex, v);
+ notifyItemChanged(mTileDividerIndex);
+ notifyDataSetChanged();
}
}
}).setNegativeButton(android.R.string.cancel, null)
@@ -331,40 +340,12 @@
}
private boolean move(int from, int to, View v) {
- if (to >= mEditIndex) {
- if (from < mEditIndex) {
- // Removing a tile.
- // 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() - 1) {
- notifyItemChanged(mTileDividerIndex);
- }
- if (to <= mTileDividerIndex) {
- to = mTileDividerIndex;
- }
- }
- } else {
- if (to > mEditIndex) {
- // Don't allow tiles to be dragged around when they aren't added.
- to = from;
- }
- // Allow the case where to == mEditIndex to fall through and swap which
- // side the tile is currently on.
- // This lets the the cases where all tiles are on one side of the line
- // work.
- }
+ if (to == from) {
+ return true;
}
CharSequence fromLabel = mTiles.get(from).state.label;
move(from, to, mTiles);
updateDividerLocations();
- if (to == from) {
- return true;
- }
CharSequence announcement;
if (to >= mEditIndex) {
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_REMOVE_SPEC,
@@ -424,7 +405,6 @@
private <T> void move(int from, int to, List<T> list) {
list.add(to, list.remove(from));
notifyItemMoved(from, to);
- notifyItemChanged(to);
}
public class Holder extends ViewHolder {
@@ -482,9 +462,16 @@
}
};
- private final ItemDecoration mDecoration = new ItemDecoration() {
- // TODO: Move this to resource.
- private final ColorDrawable mDrawable = new ColorDrawable(0xff384248);
+ private class TileItemDecoration extends ItemDecoration {
+ private final ColorDrawable mDrawable;
+
+ private TileItemDecoration(Context context) {
+ TypedArray ta =
+ context.obtainStyledAttributes(new int[]{android.R.attr.colorSecondary});
+ mDrawable = new ColorDrawable(ta.getColor(0, 0));
+ ta.recycle();
+ }
+
@Override
public void onDraw(Canvas c, RecyclerView parent, State state) {
@@ -496,7 +483,7 @@
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final ViewHolder holder = parent.getChildViewHolder(child);
- if (holder.getAdapterPosition() < mEditIndex) {
+ if (holder.getAdapterPosition() < mEditIndex && !(child instanceof TextView)) {
continue;
}
@@ -527,7 +514,15 @@
@Override
public void onSelectedChanged(ViewHolder viewHolder, int actionState) {
super.onSelectedChanged(viewHolder, actionState);
+ if (actionState != ItemTouchHelper.ACTION_STATE_DRAG) {
+ viewHolder = null;
+ }
+ if (viewHolder == mCurrentDrag) return;
if (mCurrentDrag != null) {
+ int position = mCurrentDrag.getAdapterPosition();
+ TileInfo info = mTiles.get(position);
+ mCurrentDrag.mTileView.setShowAppLabel(
+ position > mEditIndex && !info.isSystem);
mCurrentDrag.stopDrag();
mCurrentDrag = null;
}
@@ -544,6 +539,12 @@
}
@Override
+ public boolean canDropOver(RecyclerView recyclerView, ViewHolder current,
+ ViewHolder target) {
+ return target.getAdapterPosition() <= mEditIndex + 1;
+ }
+
+ @Override
public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) {
if (viewHolder.getItemViewType() == TYPE_EDIT) {
return makeMovementFlags(0, 0);
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 3d192e5..40ef6eb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -161,7 +161,7 @@
addTile(spec, appLabel, state, false);
continue;
}
- if (info.serviceInfo.icon == 0) {
+ if (info.serviceInfo.icon == 0 && info.serviceInfo.applicationInfo.icon == 0) {
continue;
}
Drawable icon = info.serviceInfo.loadIcon(pm);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 23a3ca1..d3f5d26 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -71,17 +71,12 @@
super(host);
mWindowManager = WindowManagerGlobal.getWindowManagerService();
mComponent = ComponentName.unflattenFromString(action);
+ mTile = new Tile(mComponent);
+ setTileIcon();
mServiceManager = host.getTileServices().getTileWrapper(this);
mService = mServiceManager.getTileService();
mServiceManager.setTileChangeListener(this);
- mTile = new Tile(mComponent);
mUser = ActivityManager.getCurrentUser();
- setTileIcon();
- try {
- mService.setQSTile(mTile);
- } catch (RemoteException e) {
- // Called through wrapper, won't happen here.
- }
}
private void setTileIcon() {
@@ -89,11 +84,13 @@
PackageManager pm = mContext.getPackageManager();
ServiceInfo info = pm.getServiceInfo(mComponent,
PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
+ int icon = info.icon != 0 ? info.icon
+ : info.applicationInfo.icon;
// Update the icon if its not set or is the default icon.
boolean updateIcon = mTile.getIcon() == null
|| iconEquals(mTile.getIcon(), mDefaultIcon);
- mDefaultIcon = info.icon != 0 ? android.graphics.drawable.Icon
- .createWithResource(mComponent.getPackageName(), info.icon) : null;
+ mDefaultIcon = icon != 0 ? android.graphics.drawable.Icon
+ .createWithResource(mComponent.getPackageName(), icon) : null;
if (updateIcon) {
mTile.setIcon(mDefaultIcon);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
index 3830ac5..407453c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
@@ -35,16 +35,6 @@
return mService.asBinder();
}
- public boolean setQSTile(Tile tile) {
- try {
- mService.setQSTile(tile);
- return true;
- } catch (Exception e) {
- Log.d(TAG, "Caught exception from TileService", e);
- return false;
- }
- }
-
public boolean onTileAdded() {
try {
mService.onTileAdded();
@@ -95,16 +85,6 @@
}
}
- public boolean setQSService(IQSService service) {
- try {
- mService.setQSService(service);
- return true;
- } catch (Exception e) {
- Log.d(TAG, "Caught exception from TileService", e);
- return false;
- }
- }
-
public boolean onUnlockComplete() {
try {
mService.onUnlockComplete();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index 87d6307..79f9de6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -71,23 +71,24 @@
private Set<Integer> mQueuedMessages = new ArraySet<>();
private QSTileServiceWrapper mWrapper;
private boolean mListening;
- private Tile mTile;
private IBinder mClickBinder;
private int mBindTryCount;
private boolean mBound;
@VisibleForTesting
boolean mReceiverRegistered;
- private IQSService mService;
private boolean mUnbindImmediate;
private TileChangeListener mChangeListener;
// Return value from bindServiceAsUser, determines whether safe to call unbind.
private boolean mIsBound;
- public TileLifecycleManager(Handler handler, Context context, Intent intent, UserHandle user) {
+ public TileLifecycleManager(Handler handler, Context context, IQSService service,
+ Tile tile, Intent intent, UserHandle user) {
mContext = context;
mHandler = handler;
mIntent = intent;
+ mIntent.putExtra(TileService.EXTRA_SERVICE, service.asBinder());
+ mIntent.putExtra(TileService.EXTRA_COMPONENT, intent.getComponent());
mUser = user;
if (DEBUG) Log.d(TAG, "Creating " + mIntent + " " + mUser);
}
@@ -164,14 +165,6 @@
service.linkToDeath(this, 0);
} catch (RemoteException e) {
}
- if (!wrapper.setQSService(mService)) {
- handleDeath();
- return;
- }
- if (!wrapper.setQSTile(mTile)) {
- handleDeath();
- return;
- }
mWrapper = wrapper;
handlePendingMessages();
}
@@ -255,15 +248,6 @@
}
}
- @Override
- public void setQSTile(Tile tile) {
- if (DEBUG) Log.d(TAG, "setQSTile " + tile);
- mTile = tile;
- if (mWrapper != null && !mWrapper.setQSTile(tile)) {
- handleDeath();
- }
- }
-
private boolean checkComponentState() {
PackageManager pm = mContext.getPackageManager();
if (!isPackageAvailable(pm) || !isComponentAvailable(pm)) {
@@ -347,14 +331,6 @@
}
@Override
- public void setQSService(IQSService service) {
- mService = service;
- if (mWrapper == null || !mWrapper.setQSService(service)) {
- handleDeath();
- }
- }
-
- @Override
public void onTileAdded() {
if (DEBUG) Log.d(TAG, "onTileAdded");
if (mWrapper == null || !mWrapper.onTileAdded()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
index ce9bbf4..3d030f9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -27,6 +27,7 @@
import android.os.Handler;
import android.os.UserHandle;
import android.service.quicksettings.IQSTileService;
+import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
@@ -68,9 +69,10 @@
// This defaults to true to ensure tiles start out unavailable.
private boolean mPendingBind = true;
- TileServiceManager(TileServices tileServices, Handler handler, ComponentName component) {
+ TileServiceManager(TileServices tileServices, Handler handler, ComponentName component,
+ Tile tile) {
this(tileServices, handler, new TileLifecycleManager(handler,
- tileServices.getContext(), new Intent().setComponent(component),
+ tileServices.getContext(), tileServices, tile, new Intent().setComponent(component),
new UserHandle(ActivityManager.getCurrentUser())));
}
@@ -80,7 +82,6 @@
mServices = tileServices;
mHandler = handler;
mStateManager = tileLifecycleManager;
- mStateManager.setQSService(tileServices);
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index 2ab6b5f..6f0bed2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -78,7 +78,7 @@
public TileServiceManager getTileWrapper(CustomTile tile) {
ComponentName component = tile.getComponent();
- TileServiceManager service = onCreateTileService(component);
+ TileServiceManager service = onCreateTileService(component, tile.getQsTile());
synchronized (mServices) {
mServices.put(tile, service);
mTiles.put(component, tile);
@@ -86,8 +86,8 @@
return service;
}
- protected TileServiceManager onCreateTileService(ComponentName component) {
- return new TileServiceManager(this, mHandler, component);
+ protected TileServiceManager onCreateTileService(ComponentName component, Tile tile) {
+ return new TileServiceManager(this, mHandler, component, tile);
}
public void freeService(CustomTile tile, TileServiceManager service) {
@@ -263,6 +263,16 @@
}
@Override
+ public Tile getTile(ComponentName componentName) {
+ verifyCaller(componentName.getPackageName());
+ CustomTile customTile = getTileForComponent(componentName);
+ if (customTile != null) {
+ return customTile.getQsTile();
+ }
+ return null;
+ }
+
+ @Override
public void startUnlockAndRun(Tile tile) {
ComponentName componentName = tile.getComponentName();
verifyCaller(componentName.getPackageName());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 18191cf..0de5105 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -95,14 +95,6 @@
}
@Override
- protected void handleSecondaryClick() {
- boolean dataEnabled = mDataController.isMobileDataSupported()
- && mDataController.isMobileDataEnabled();
- MetricsLogger.action(mContext, MetricsEvent.QS_CELLULAR_TOGGLE, !dataEnabled);
- mDataController.setMobileDataEnabled(!dataEnabled);
- }
-
- @Override
public CharSequence getTileLabel() {
return mContext.getString(R.string.quick_settings_cellular_detail_title);
}
@@ -152,8 +144,8 @@
}
state.contentDescription = state.contentDescription + "," + r.getString(
R.string.accessibility_quick_settings_open_settings, getTileLabel());
- state.expandedAccessibilityClassName = Button.class.getName();
- state.minimalAccessibilityClassName = Switch.class.getName();
+ state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
+ = Button.class.getName();
state.value = mDataController.isMobileDataSupported()
&& mDataController.isMobileDataEnabled();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
index bad4e79..a63eabc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles;
+import android.annotation.ColorInt;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -24,6 +25,7 @@
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.android.settingslib.Utils;
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
@@ -64,7 +66,7 @@
final Resources res = mContext.getResources();
final int titleId;
final long bytes;
- int usageColor = R.color.system_accent_color;
+ @ColorInt int usageColor = 0;
final String top;
String bottom = null;
if (info.usageLevel < info.warningLevel || info.limitLevel <= 0) {
@@ -89,14 +91,18 @@
formatBytes(info.usageLevel));
bottom = res.getString(R.string.quick_settings_cellular_detail_data_limit,
formatBytes(info.limitLevel));
- usageColor = R.color.system_warning_color;
+ usageColor = mContext.getColor(R.color.system_warning_color);
+ }
+
+ if (usageColor == 0) {
+ usageColor = Utils.getColorAccent(mContext);
}
final TextView title = (TextView) findViewById(android.R.id.title);
title.setText(titleId);
final TextView usage = (TextView) findViewById(R.id.usage_text);
usage.setText(formatBytes(bytes));
- usage.setTextColor(mContext.getColor(usageColor));
+ usage.setTextColor(usageColor);
final DataUsageGraph graph = (DataUsageGraph) findViewById(R.id.usage_graph);
graph.setLevels(info.limitLevel, info.warningLevel, info.usageLevel);
final TextView carrier = (TextView) findViewById(R.id.usage_carrier_text);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 1c134c1..016c4b7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -36,15 +36,16 @@
import com.android.systemui.statusbar.policy.HotspotController;
/** Quick settings tile: Hotspot **/
-public class HotspotTile extends QSTile<QSTile.BooleanState> {
+public class HotspotTile extends QSTile<QSTile.AirplaneBooleanState> {
private final AnimationIcon mEnable =
new AnimationIcon(R.drawable.ic_hotspot_enable_animation,
R.drawable.ic_hotspot_disable);
private final AnimationIcon mDisable =
new AnimationIcon(R.drawable.ic_hotspot_disable_animation,
R.drawable.ic_hotspot_enable);
- private final Icon mUnavailable =
- ResourceIcon.get(R.drawable.ic_hotspot_unavailable);
+ private final Icon mDisableNoAnimation = ResourceIcon.get(R.drawable.ic_hotspot_enable);
+ private final Icon mUnavailable = ResourceIcon.get(R.drawable.ic_hotspot_unavailable);
+
private final HotspotController mController;
private final Callback mCallback = new Callback();
private final GlobalSetting mAirplaneMode;
@@ -72,8 +73,8 @@
}
@Override
- public BooleanState newTileState() {
- return new BooleanState();
+ public AirplaneBooleanState newTileState() {
+ return new AirplaneBooleanState();
}
@Override
@@ -84,10 +85,9 @@
mController.addCallback(mCallback);
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- mContext.registerReceiver(mReceiver, filter);
+ refreshState();
} else {
mController.removeCallback(mCallback);
- mContext.unregisterReceiver(mReceiver);
}
mAirplaneMode.setListening(listening);
}
@@ -113,7 +113,7 @@
}
@Override
- protected void handleUpdateState(BooleanState state, Object arg) {
+ protected void handleUpdateState(AirplaneBooleanState state, Object arg) {
state.label = mContext.getString(R.string.quick_settings_hotspot_label);
checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_CONFIG_TETHERING);
@@ -123,12 +123,16 @@
state.value = mController.isHotspotEnabled();
}
state.icon = state.value ? mEnable : mDisable;
- if (mAirplaneMode.getValue() != 0) {
+ boolean wasAirplane = state.isAirplaneMode;
+ state.isAirplaneMode = mAirplaneMode.getValue() != 0;
+ if (state.isAirplaneMode) {
final int disabledColor = mHost.getContext().getColor(R.color.qs_tile_tint_unavailable);
state.label = new SpannableStringBuilder().append(state.label,
new ForegroundColorSpan(disabledColor),
SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE);
state.icon = mUnavailable;
+ } else if (wasAirplane) {
+ state.icon = mDisableNoAnimation;
}
state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
= Switch.class.getName();
@@ -155,13 +159,4 @@
refreshState(enabled);
}
};
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(intent.getAction())) {
- refreshState();
- }
- }
- };
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 1a944ce..94231c6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -29,6 +29,7 @@
import android.app.AppGlobals;
import android.app.IActivityManager;
import android.app.ITaskStackListener;
+import android.app.UiModeManager;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -38,6 +39,7 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -83,6 +85,7 @@
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
@@ -234,6 +237,13 @@
mDummyIcon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
mDummyIcon.eraseColor(0xFF999999);
}
+
+ UiModeManager uiModeManager = (UiModeManager) context.
+ getSystemService(Context.UI_MODE_SERVICE);
+ if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
+ Collections.addAll(sRecentsBlacklist,
+ res.getStringArray(R.array.recents_tv_blacklist_array));
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index e6cbbea..d789477 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -60,6 +60,7 @@
import android.widget.ImageView;
import com.android.systemui.R;
+import com.android.systemui.SystemUI;
import java.io.File;
import java.io.FileOutputStream;
@@ -165,11 +166,6 @@
c.drawColor(overlayColor);
c.setBitmap(null);
- // swap "System UI" out for "Android System"
- final Bundle extras = new Bundle();
- extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
- context.getString(com.android.internal.R.string.android_system_label));
-
// Show the intermediate notification
mTickerAddSpace = !mTickerAddSpace;
mNotificationManager = nManager;
@@ -187,9 +183,9 @@
.setCategory(Notification.CATEGORY_PROGRESS)
.setWhen(now)
.setShowWhen(true)
- .addExtras(extras)
.setColor(r.getColor(
com.android.internal.R.color.system_notification_accent_color));
+ SystemUI.overrideNotificationAppName(context, mPublicNotificationBuilder);
mNotificationBuilder = new Notification.Builder(context)
.setTicker(r.getString(R.string.screenshot_saving_ticker)
@@ -199,11 +195,11 @@
.setSmallIcon(R.drawable.stat_notify_image)
.setWhen(now)
.setShowWhen(true)
- .addExtras(extras)
.setColor(r.getColor(com.android.internal.R.color.system_notification_accent_color))
.setStyle(mNotificationStyle)
.setPublicVersion(mPublicNotificationBuilder.build());
mNotificationBuilder.setFlag(Notification.FLAG_NO_CLEAR, true);
+ SystemUI.overrideNotificationAppName(context, mNotificationBuilder);
mNotificationManager.notify(R.id.notification_screenshot, mNotificationBuilder.build());
@@ -864,6 +860,7 @@
.setAutoCancel(true)
.setColor(context.getColor(
com.android.internal.R.color.system_notification_accent_color));
+ SystemUI.overrideNotificationAppName(context, b);
Notification n = new Notification.BigTextStyle(b)
.bigText(errorMsg)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 91889d3..8ee34a4c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -134,6 +134,7 @@
= SystemProperties.getBoolean("debug.child_notifs", true);
public static final boolean FORCE_REMOTE_INPUT_HISTORY =
SystemProperties.getBoolean("debug.force_remoteinput_history", false);
+ private static boolean ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = false;
protected static final int MSG_SHOW_RECENT_APPS = 1019;
protected static final int MSG_HIDE_RECENT_APPS = 1020;
@@ -704,10 +705,13 @@
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
mSettingsObserver,
UserHandle.USER_ALL);
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT), false,
- mSettingsObserver,
- UserHandle.USER_ALL);
+ if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT),
+ false,
+ mSettingsObserver,
+ UserHandle.USER_ALL);
+ }
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
@@ -840,7 +844,6 @@
new Intent(BANNER_ACTION_SETUP).setPackage(packageName),
PendingIntent.FLAG_CANCEL_CURRENT);
- final Resources res = mContext.getResources();
final int colorRes = com.android.internal.R.color.system_notification_accent_color;
Notification.Builder note = new Notification.Builder(mContext)
.setSmallIcon(R.drawable.ic_android)
@@ -856,6 +859,7 @@
.addAction(R.drawable.ic_settings,
mContext.getString(R.string.hidden_notifications_setup),
setupIntent);
+ overrideNotificationAppName(mContext, note);
NotificationManager noMan =
(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -1079,10 +1083,10 @@
pkgicon = pmUser.getDefaultActivityIcon();
}
- ((ImageView) row.findViewById(R.id.app_icon)).setImageDrawable(pkgicon);
- ((TextView) row.findViewById(R.id.pkgname)).setText(appname);
+ ((ImageView) guts.findViewById(R.id.app_icon)).setImageDrawable(pkgicon);
+ ((TextView) guts.findViewById(R.id.pkgname)).setText(appname);
- final View settingsButton = guts.findViewById(R.id.more_settings);
+ final TextView settingsButton = (TextView) guts.findViewById(R.id.more_settings);
if (appUid >= 0) {
final int appUidF = appUid;
settingsButton.setOnClickListener(new View.OnClickListener() {
@@ -1092,11 +1096,16 @@
startAppNotificationSettingsActivity(pkg, appUidF);
}
});
+ settingsButton.setText(R.string.notification_more_settings);
} else {
settingsButton.setVisibility(View.GONE);
}
- row.findViewById(R.id.done).setOnClickListener(new View.OnClickListener() {
+ guts.bindImportance(pmUser, sbn, mNotificationData.getImportance(sbn.getKey()));
+
+ final TextView doneButton = (TextView) guts.findViewById(R.id.done);
+ doneButton.setText(R.string.notification_done);
+ doneButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// If the user has security enabled, show challenge if the setting is changed.
@@ -1116,7 +1125,6 @@
}
}
});
- guts.bindImportance(pmUser, sbn, row, mNotificationData.getImportance(sbn.getKey()));
}
private void saveImportanceCloseControls(StatusBarNotification sbn,
@@ -2304,16 +2312,20 @@
final boolean allowedByDpm = (dpmFlags
& DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
- final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
- 0,
- mCurrentUserId) != 0;
- final boolean remoteInputDpm = (dpmFlags
- & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0;
-
-
setShowLockscreenNotifications(show && allowedByDpm);
- setLockScreenAllowRemoteInput(remoteInput && remoteInputDpm);
+
+ if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
+ final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
+ 0,
+ mCurrentUserId) != 0;
+ final boolean remoteInputDpm =
+ (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0;
+
+ setLockScreenAllowRemoteInput(remoteInput && remoteInputDpm);
+ } else {
+ setLockScreenAllowRemoteInput(false);
+ }
}
protected abstract void setAreThereNotifications();
@@ -2483,7 +2495,7 @@
}
protected boolean shouldPeek(Entry entry, StatusBarNotification sbn) {
- if (isDeviceInVrMode()) {
+ if (!mUseHeadsUp || isDeviceInVrMode()) {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 7b23c80..419c91b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -23,6 +23,7 @@
import android.os.IBinder;
import android.os.Message;
import android.util.Pair;
+import android.view.KeyEvent;
import com.android.internal.os.SomeArgs;
import com.android.internal.statusbar.IStatusBar;
@@ -75,6 +76,7 @@
private static final int MSG_TOGGLE_APP_SPLIT_SCREEN = 30 << MSG_SHIFT;
private static final int MSG_APP_TRANSITION_FINISHED = 31 << MSG_SHIFT;
private static final int MSG_DISMISS_KEYBOARD_SHORTCUTS = 32 << MSG_SHIFT;
+ private static final int MSG_HANDLE_SYSNAV_KEY = 33 << MSG_SHIFT;
public static final int FLAG_EXCLUDE_NONE = 0;
public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -129,6 +131,8 @@
void addQsTile(ComponentName tile);
void remQsTile(ComponentName tile);
void clickTile(ComponentName tile);
+
+ void handleSystemNavigationKey(int arg1);
}
public CommandQueue(Callbacks callbacks) {
@@ -388,6 +392,13 @@
}
}
+ @Override
+ public void handleSystemNavigationKey(int key) {
+ synchronized (mLock) {
+ mHandler.obtainMessage(MSG_HANDLE_SYSNAV_KEY, key, 0).sendToTarget();
+ }
+ }
+
private final class H extends Handler {
public void handleMessage(Message msg) {
final int what = msg.what & MSG_MASK;
@@ -503,6 +514,9 @@
case MSG_TOGGLE_APP_SPLIT_SCREEN:
mCallbacks.toggleSplitScreen();
break;
+ case MSG_HANDLE_SYSNAV_KEY:
+ mCallbacks.handleSystemNavigationKey(msg.arg1);
+ break;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index e1d4c8a..f09eae8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -185,6 +185,7 @@
}
};
private OnClickListener mOnClickListener;
+ private boolean mHeadsupDisappearRunning;
private View mChildAfterViewWhenDismissed;
private View mGroupParentWhenDismissed;
private boolean mRefocusOnDismiss;
@@ -759,15 +760,17 @@
mRemoved = true;
mPrivateLayout.setRemoved();
- if (mChildrenContainer != null) {
- mChildrenContainer.setRemoved();
- }
}
public NotificationChildrenContainer getChildrenContainer() {
return mChildrenContainer;
}
+ public void setHeadsupDisappearRunning(boolean running) {
+ mHeadsupDisappearRunning = running;
+ mPrivateLayout.setHeadsupDisappearRunning(running);
+ }
+
public View getChildAfterViewWhenDismissed() {
return mChildAfterViewWhenDismissed;
}
@@ -1173,8 +1176,8 @@
return getMinHeight();
} else if (mIsSummaryWithChildren && !mOnKeyguard) {
return mChildrenContainer.getIntrinsicHeight();
- } else if (mIsHeadsUp) {
- if (isPinned()) {
+ } else if (mIsHeadsUp || mHeadsupDisappearRunning) {
+ if (isPinned() || mHeadsupDisappearRunning) {
return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
} else if (isExpanded()) {
return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
@@ -1300,6 +1303,10 @@
if (!animated) {
mPublicLayout.animate().cancel();
mPrivateLayout.animate().cancel();
+ if (mChildrenContainer != null) {
+ mChildrenContainer.animate().cancel();
+ mChildrenContainer.setAlpha(1f);
+ }
mPublicLayout.setAlpha(1f);
mPrivateLayout.setAlpha(1f);
mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index 9211562..016e1f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.AlertDialog;
import android.app.AppGlobals;
import android.app.Dialog;
@@ -45,15 +47,18 @@
import android.view.KeyboardShortcutInfo;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.View.AccessibilityDelegate;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager.KeyboardShortcutsReceiver;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.android.internal.app.AssistUtils;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
@@ -63,6 +68,7 @@
import java.util.List;
import static android.content.Context.LAYOUT_INFLATER_SERVICE;
+import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
/**
@@ -112,7 +118,7 @@
private KeyCharacterMap mKeyCharacterMap;
private KeyboardShortcuts(Context context) {
- this.mContext = new ContextThemeWrapper(context, android.R.style.Theme_Material_Light);
+ this.mContext = new ContextThemeWrapper(context, android.R.style.Theme_DeviceDefault_Light);
this.mPackageManager = AppGlobals.getPackageManager();
loadResources(context);
}
@@ -582,7 +588,7 @@
R.layout.keyboard_shortcuts_category_title, keyboardShortcutsLayout, false);
categoryTitle.setText(group.getLabel());
categoryTitle.setTextColor(group.isSystemGroup()
- ? mContext.getColor(R.color.ksh_system_group_color)
+ ? Utils.getColorAccent(mContext)
: mContext.getColor(R.color.ksh_application_group_color));
keyboardShortcutsLayout.addView(categoryTitle);
@@ -591,7 +597,7 @@
final int itemsSize = group.getItems().size();
for (int j = 0; j < itemsSize; j++) {
KeyboardShortcutInfo info = group.getItems().get(j);
- List<StringOrDrawable> shortcutKeys = getHumanReadableShortcutKeys(info);
+ List<StringDrawableContainer> shortcutKeys = getHumanReadableShortcutKeys(info);
if (shortcutKeys == null) {
// Ignore shortcuts we can't display keys for.
Log.w(TAG, "Keyboard Shortcut contains unsupported keys, skipping.");
@@ -621,25 +627,33 @@
.findViewById(R.id.keyboard_shortcuts_item_container);
final int shortcutKeysSize = shortcutKeys.size();
for (int k = 0; k < shortcutKeysSize; k++) {
- StringOrDrawable shortcutRepresentation = shortcutKeys.get(k);
- if (shortcutRepresentation.drawable != null) {
+ StringDrawableContainer shortcutRepresentation = shortcutKeys.get(k);
+ if (shortcutRepresentation.mDrawable != null) {
ImageView shortcutKeyIconView = (ImageView) inflater.inflate(
R.layout.keyboard_shortcuts_key_icon_view, shortcutItemsContainer,
false);
Bitmap bitmap = Bitmap.createBitmap(shortcutKeyIconItemHeightWidth,
shortcutKeyIconItemHeightWidth, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
- shortcutRepresentation.drawable.setBounds(0, 0, canvas.getWidth(),
+ shortcutRepresentation.mDrawable.setBounds(0, 0, canvas.getWidth(),
canvas.getHeight());
- shortcutRepresentation.drawable.draw(canvas);
+ shortcutRepresentation.mDrawable.draw(canvas);
shortcutKeyIconView.setImageBitmap(bitmap);
+ shortcutKeyIconView.setImportantForAccessibility(
+ IMPORTANT_FOR_ACCESSIBILITY_YES);
+ shortcutKeyIconView.setAccessibilityDelegate(
+ new ShortcutKeyAccessibilityDelegate(
+ shortcutRepresentation.mString));
shortcutItemsContainer.addView(shortcutKeyIconView);
- } else if (shortcutRepresentation.string != null) {
+ } else if (shortcutRepresentation.mString != null) {
TextView shortcutKeyTextView = (TextView) inflater.inflate(
R.layout.keyboard_shortcuts_key_view, shortcutItemsContainer,
false);
shortcutKeyTextView.setMinimumWidth(shortcutKeyTextItemMinWidth);
- shortcutKeyTextView.setText(shortcutRepresentation.string);
+ shortcutKeyTextView.setText(shortcutRepresentation.mString);
+ shortcutKeyTextView.setAccessibilityDelegate(
+ new ShortcutKeyAccessibilityDelegate(
+ shortcutRepresentation.mString));
shortcutItemsContainer.addView(shortcutKeyTextView);
}
}
@@ -655,19 +669,20 @@
}
}
- private List<StringOrDrawable> getHumanReadableShortcutKeys(KeyboardShortcutInfo info) {
- List<StringOrDrawable> shortcutKeys = getHumanReadableModifiers(info);
+ private List<StringDrawableContainer> getHumanReadableShortcutKeys(KeyboardShortcutInfo info) {
+ List<StringDrawableContainer> shortcutKeys = getHumanReadableModifiers(info);
if (shortcutKeys == null) {
return null;
}
- String displayLabelString = null;
- Drawable displayLabelDrawable = null;
+ String shortcutKeyString = null;
+ Drawable shortcutKeyDrawable = null;
if (info.getBaseCharacter() > Character.MIN_VALUE) {
- displayLabelString = String.valueOf(info.getBaseCharacter());
+ shortcutKeyString = String.valueOf(info.getBaseCharacter());
} else if (mSpecialCharacterDrawables.get(info.getKeycode()) != null) {
- displayLabelDrawable = mSpecialCharacterDrawables.get(info.getKeycode());
+ shortcutKeyDrawable = mSpecialCharacterDrawables.get(info.getKeycode());
+ shortcutKeyString = mSpecialCharacterNames.get(info.getKeycode());
} else if (mSpecialCharacterNames.get(info.getKeycode()) != null) {
- displayLabelString = mSpecialCharacterNames.get(info.getKeycode());
+ shortcutKeyString = mSpecialCharacterNames.get(info.getKeycode());
} else {
// Special case for shortcuts with no base key or keycode.
if (info.getKeycode() == KeyEvent.KEYCODE_UNKNOWN) {
@@ -675,22 +690,23 @@
}
char displayLabel = mKeyCharacterMap.getDisplayLabel(info.getKeycode());
if (displayLabel != 0) {
- displayLabelString = String.valueOf(displayLabel);
+ shortcutKeyString = String.valueOf(displayLabel);
} else {
return null;
}
}
- if (displayLabelDrawable != null) {
- shortcutKeys.add(new StringOrDrawable(displayLabelDrawable));
- } else if (displayLabelString != null) {
- shortcutKeys.add(new StringOrDrawable(displayLabelString.toUpperCase()));
+ if (shortcutKeyString != null) {
+ shortcutKeys.add(new StringDrawableContainer(shortcutKeyString, shortcutKeyDrawable));
+ } else {
+ Log.w(TAG, "Keyboard Shortcut does not have a text representation, skipping.");
}
+
return shortcutKeys;
}
- private List<StringOrDrawable> getHumanReadableModifiers(KeyboardShortcutInfo info) {
- final List<StringOrDrawable> shortcutKeys = new ArrayList<>();
+ private List<StringDrawableContainer> getHumanReadableModifiers(KeyboardShortcutInfo info) {
+ final List<StringDrawableContainer> shortcutKeys = new ArrayList<>();
int modifiers = info.getModifiers();
if (modifiers == 0) {
return shortcutKeys;
@@ -698,13 +714,9 @@
for(int i = 0; i < mModifierNames.size(); ++i) {
final int supportedModifier = mModifierNames.keyAt(i);
if ((modifiers & supportedModifier) != 0) {
- if (mModifierDrawables.get(supportedModifier) != null) {
- shortcutKeys.add(new StringOrDrawable(
- mModifierDrawables.get(supportedModifier)));
- } else {
- shortcutKeys.add(new StringOrDrawable(
- mModifierNames.get(supportedModifier).toUpperCase()));
- }
+ shortcutKeys.add(new StringDrawableContainer(
+ mModifierNames.get(supportedModifier),
+ mModifierDrawables.get(supportedModifier)));
modifiers &= ~supportedModifier;
}
}
@@ -715,16 +727,31 @@
return shortcutKeys;
}
- private static final class StringOrDrawable {
- public String string;
- public Drawable drawable;
+ private final class ShortcutKeyAccessibilityDelegate extends AccessibilityDelegate {
+ private String mContentDescription;
- public StringOrDrawable(String string) {
- this.string = string;
+ ShortcutKeyAccessibilityDelegate(String contentDescription) {
+ mContentDescription = contentDescription;
}
- public StringOrDrawable(Drawable drawable) {
- this.drawable = drawable;
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ if (mContentDescription != null) {
+ info.setContentDescription(mContentDescription.toLowerCase());
+ }
+ }
+ }
+
+ private static final class StringDrawableContainer {
+ @NonNull
+ public String mString;
+ @Nullable
+ public Drawable mDrawable;
+
+ StringDrawableContainer(String string, Drawable drawable) {
+ mString = string;
+ mDrawable = drawable;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 30ac9ca..9fd09d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -119,6 +119,7 @@
private int mContentHeightAtAnimationStart = UNDEFINED;
private boolean mFocusOnVisibilityChange;
+ private boolean mHeadsupDisappearRunning;
public NotificationContentView(Context context, AttributeSet attrs) {
@@ -446,7 +447,8 @@
boolean transitioningBetweenHunAndExpanded =
isTransitioningFromTo(VISIBLE_TYPE_HEADSUP, VISIBLE_TYPE_EXPANDED) ||
isTransitioningFromTo(VISIBLE_TYPE_EXPANDED, VISIBLE_TYPE_HEADSUP);
- boolean pinned = !isVisibleOrTransitioning(VISIBLE_TYPE_CONTRACTED) && mIsHeadsUp;
+ boolean pinned = !isVisibleOrTransitioning(VISIBLE_TYPE_CONTRACTED)
+ && (mIsHeadsUp || mHeadsupDisappearRunning);
if (transitioningBetweenHunAndExpanded || pinned) {
return Math.min(mHeadsUpChild.getHeight(), mExpandedChild.getHeight());
}
@@ -830,7 +832,7 @@
return VISIBLE_TYPE_SINGLELINE;
}
- if (mIsHeadsUp && mHeadsUpChild != null) {
+ if ((mIsHeadsUp || mHeadsupDisappearRunning) && mHeadsUpChild != null) {
if (viewHeight <= mHeadsUpChild.getHeight() || noExpandedChild) {
return VISIBLE_TYPE_HEADSUP;
} else {
@@ -1153,6 +1155,11 @@
}
}
+ public void setHeadsupDisappearRunning(boolean headsupDisappearRunning) {
+ mHeadsupDisappearRunning = headsupDisappearRunning;
+ selectLayout(false /* animate */, true /* force */);
+ }
+
public void setFocusOnVisibilityChange() {
mFocusOnVisibilityChange = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index 5bbca15..b66a4fb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -173,7 +173,7 @@
}
void bindImportance(final PackageManager pm, final StatusBarNotification sbn,
- final ExpandableNotificationRow row, final int importance) {
+ final int importance) {
mINotificationManager = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
mStartingUserImportance = NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
@@ -191,8 +191,8 @@
// unlikely.
}
- final View importanceSlider = row.findViewById(R.id.importance_slider);
- final View importanceButtons = row.findViewById(R.id.importance_buttons);
+ final View importanceSlider = findViewById(R.id.importance_slider);
+ final View importanceButtons = findViewById(R.id.importance_buttons);
if (mShowSlider) {
bindSlider(importanceSlider, systemApp);
importanceSlider.setVisibility(View.VISIBLE);
@@ -256,6 +256,8 @@
} else {
mReset.setText(mContext.getString(R.string.do_not_silence_block));
}
+ mBlock.setText(mContext.getString(R.string.block));
+ mSilent.setText(mContext.getString(R.string.show_silently));
if (importance == NotificationListenerService.Ranking.IMPORTANCE_LOW) {
mSilent.setChecked(true);
} else {
@@ -264,7 +266,7 @@
}
private void bindSlider(final View importanceSlider, final boolean systemApp) {
- mActiveSliderTint = loadColorStateList(R.color.notification_guts_slider_color);
+ mActiveSliderTint = ColorStateList.valueOf(Utils.getColorAccent(mContext));
mInactiveSliderTint = loadColorStateList(R.color.notification_guts_disabled_slider_color);
mImportanceSummary = ((TextView) importanceSlider.findViewById(R.id.summary));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
index 5fea674..6cbacea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -130,6 +130,28 @@
}
}
+ public void closeRemoteInputs() {
+ if (mOpen.size() == 0) {
+ return;
+ }
+
+ // Make a copy because closing the remote inputs will modify mOpen.
+ ArrayList<NotificationData.Entry> list = new ArrayList<>(mOpen.size());
+ for (int i = mOpen.size() - 1; i >= 0; i--) {
+ NotificationData.Entry item = mOpen.get(i).get();
+ if (item != null && item.row != null) {
+ list.add(item);
+ }
+ }
+
+ for (int i = list.size() - 1; i >= 0; i--) {
+ NotificationData.Entry item = list.get(i);
+ if (item.row != null) {
+ item.row.closeRemoteInput();
+ }
+ }
+ }
+
public interface Callback {
default void onRemoteInputActive(boolean active) {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index a2ad46a..74caa53 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -237,6 +237,14 @@
super.onDetachedFromWindow();
}
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+
+ // Re-run all checks against the tint area for all icons
+ applyIconTint();
+ }
+
// From SecurityController.
@Override
public void onStateChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
index f75f3574..1ff2b13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
@@ -20,6 +20,7 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.view.View;
import android.view.ViewGroup;
@@ -194,7 +195,7 @@
for (Integer viewType : mTransformedViews.keySet()) {
TransformState ownState = getCurrentState(viewType);
if (ownState != null) {
- ownState.setVisible(visible);
+ ownState.setVisible(visible, false /* force */);
ownState.recycle();
}
}
@@ -252,6 +253,19 @@
}
}
+ public void resetTransformedView(View view) {
+ TransformState state = TransformState.createFrom(view);
+ state.setVisible(true /* visible */, true /* force */);
+ state.recycle();
+ }
+
+ /**
+ * @return a set of all views are being transformed.
+ */
+ public ArraySet<View> getAllTransformingViews() {
+ return new ArraySet<>(mTransformedViews.values());
+ }
+
public static abstract class CustomTransformation {
/**
* Transform a state to the given view
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java
index 8463e06..9501f90 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java
@@ -123,8 +123,9 @@
}
}
- public void setVisible(boolean visible) {
- super.setVisible(visible);
+ @Override
+ public void setVisible(boolean visible, boolean force) {
+ super.setVisible(visible, force);
if (!(mTransformedView instanceof NotificationHeaderView)) {
return;
}
@@ -132,11 +133,13 @@
int childCount = header.getChildCount();
for (int i = 0; i < childCount; i++) {
View headerChild = header.getChildAt(i);
- if (headerChild.getVisibility() == View.GONE) {
+ if (!force && headerChild.getVisibility() == View.GONE) {
continue;
}
headerChild.animate().cancel();
- headerChild.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+ if (headerChild.getVisibility() != View.GONE) {
+ headerChild.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+ }
if (headerChild == mExpandButton) {
headerChild.setAlpha(visible ? 1.0f : 0.0f);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
index 1bfbaa2..7794d5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
@@ -22,18 +22,17 @@
import android.content.Context;
import android.graphics.Color;
import android.graphics.ColorFilter;
-import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.service.notification.StatusBarNotification;
+import android.util.ArraySet;
import android.view.NotificationHeaderView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
-import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.ViewInvertHelper;
import com.android.systemui.statusbar.ExpandableNotificationRow;
@@ -92,12 +91,25 @@
@Override
public void notifyContentUpdated(StatusBarNotification notification) {
super.notifyContentUpdated(notification);
+
+ ArraySet<View> previousViews = mTransformationHelper.getAllTransformingViews();
+
// Reinspect the notification.
resolveHeaderViews();
updateInvertHelper();
updateTransformedTypes();
addRemainingTransformTypes();
updateCropToPaddingForImageViews();
+
+ // We need to reset all views that are no longer transforming in case a view was previously
+ // transformed, but now we decided to transform its container instead.
+ ArraySet<View> currentViews = mTransformationHelper.getAllTransformingViews();
+ for (int i = 0; i < previousViews.size(); i++) {
+ View view = previousViews.valueAt(i);
+ if (!currentViews.contains(view)) {
+ mTransformationHelper.resetTransformedView(view);
+ }
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index 7d3da1b..f0f5c8d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -301,6 +301,9 @@
}
public static void setClippingDeactivated(final View transformedView, boolean deactivated) {
+ if (!(transformedView.getParent() instanceof ViewGroup)) {
+ return;
+ }
ViewGroup view = (ViewGroup) transformedView.getParent();
while (true) {
ArraySet<View> clipSet = (ArraySet<View>) view.getTag(CLIP_CLIPPING_SET);
@@ -456,12 +459,14 @@
mTransformationEndY = UNDEFINED;
}
- public void setVisible(boolean visible) {
- if (mTransformedView.getVisibility() == View.GONE) {
+ public void setVisible(boolean visible, boolean force) {
+ if (!force && mTransformedView.getVisibility() == View.GONE) {
return;
}
+ if (mTransformedView.getVisibility() != View.GONE) {
+ mTransformedView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+ }
mTransformedView.animate().cancel();
- mTransformedView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
mTransformedView.setAlpha(visible ? 1.0f : 0.0f);
resetTransformedView();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 7db2870..d5ff0b35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -56,6 +56,7 @@
private BatteryController mBatteryController;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
+ private UserSwitcherController mUserSwitcherController;
private int mSystemIconsSwitcherHiddenExpandedMargin;
private View mSystemIconsContainer;
@@ -149,6 +150,15 @@
} else if (mMultiUserSwitch.getParent() == this && mKeyguardUserSwitcherShowing) {
removeView(mMultiUserSwitch);
}
+ if (mKeyguardUserSwitcher == null) {
+ // If we have no keyguard switcher, the screen width is under 600dp. In this case,
+ // we don't show the multi-user avatar unless there is more than 1 user on the device.
+ if (mUserSwitcherController.getSwitchableUserCount() > 1) {
+ mMultiUserSwitch.setVisibility(View.VISIBLE);
+ } else {
+ mMultiUserSwitch.setVisibility(View.GONE);
+ }
+ }
mBatteryLevel.setVisibility(mBatteryCharging ? View.VISIBLE : View.GONE);
}
@@ -187,6 +197,7 @@
}
public void setUserSwitcherController(UserSwitcherController controller) {
+ mUserSwitcherController = controller;
mMultiUserSwitch.setUserSwitcherController(controller);
}
@@ -287,6 +298,8 @@
mSystemIconsSuperContainer.animate().cancel();
mMultiUserSwitch.animate().cancel();
mMultiUserSwitch.setAlpha(1f);
+ } else {
+ updateVisibilities();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index 9ecff18d..204ab7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -213,18 +213,18 @@
return isGroupSuppressed(getGroupKey(sbn)) && sbn.getNotification().isGroupSummary();
}
- public boolean isOnlyChildInSuppressedGroup(StatusBarNotification sbn) {
- return isGroupSuppressed(sbn.getGroupKey())
- && isOnlyChild(sbn);
- }
-
private boolean isOnlyChild(StatusBarNotification sbn) {
return !sbn.getNotification().isGroupSummary()
&& getTotalNumberOfChildren(sbn) == 1;
}
public boolean isOnlyChildInGroup(StatusBarNotification sbn) {
- return isOnlyChild(sbn) && getLogicalGroupSummary(sbn) != null;
+ if (!isOnlyChild(sbn)) {
+ return false;
+ }
+ ExpandableNotificationRow logicalGroupSummary = getLogicalGroupSummary(sbn);
+ return logicalGroupSummary != null
+ && !logicalGroupSummary.getStatusBarNotification().equals(sbn);
}
private int getTotalNumberOfChildren(StatusBarNotification sbn) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 5064d8e..4b82279 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -1296,7 +1296,7 @@
}
}
- private void flingSettings(float vel, boolean expand) {
+ public void flingSettings(float vel, boolean expand) {
flingSettings(vel, expand, null, false /* isClick */);
}
@@ -1390,10 +1390,14 @@
return maxHeight;
}
- private boolean isInSettings() {
+ public boolean isInSettings() {
return mQsExpanded;
}
+ public boolean isExpanding() {
+ return mIsExpanding;
+ }
+
@Override
protected void onHeightUpdated(float expandedHeight) {
if (!mQsExpanded || mQsExpandImmediate || mIsExpanding && mQsExpandedWhenExpandingStarted) {
@@ -2108,6 +2112,7 @@
onEmptySpaceClick(x);
}
+ @Override
protected boolean onMiddleClicked() {
switch (mStatusBar.getBarState()) {
case StatusBarState.KEYGUARD:
@@ -2257,6 +2262,7 @@
mStatusBar.clearNotificationEffects();
}
+ @Override
protected boolean isPanelVisibleBecauseOfHeadsUp() {
return mHeadsUpManager.hasPinnedHeadsUp() || mHeadsUpAnimatingAway;
}
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 376f724a..12a79b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1235,6 +1235,7 @@
}
private View.OnClickListener mRecentsClickListener = new View.OnClickListener() {
+ @Override
public void onClick(View v) {
awakenDreams();
toggleRecentApps();
@@ -1299,6 +1300,7 @@
};
private final View.OnTouchListener mHomeActionListener = new View.OnTouchListener() {
+ @Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
@@ -1409,7 +1411,7 @@
if (shadeEntry == null) {
return;
}
- boolean isHeadsUped = mUseHeadsUp && shouldPeek(shadeEntry);
+ boolean isHeadsUped = shouldPeek(shadeEntry);
if (isHeadsUped) {
mHeadsUpManager.showNotification(shadeEntry);
// Mark as seen immediately
@@ -2232,6 +2234,7 @@
/**
* State is one or more of the DISABLE constants from StatusBarManager.
*/
+ @Override
public void disable(int state1, int state2, boolean animate) {
animate &= mStatusBarWindowState != WINDOW_STATE_HIDDEN;
mDisabledUnmodified1 = state1;
@@ -2461,6 +2464,7 @@
}
+ @Override
protected void updateHeadsUp(String key, Entry entry, boolean shouldPeek,
boolean alertAgain) {
final boolean wasHeadsUp = isHeadsUp(key);
@@ -2477,6 +2481,7 @@
}
}
+ @Override
protected void setHeadsUpUser(int newUserId) {
if (mHeadsUpManager != null) {
mHeadsUpManager.setUser(newUserId);
@@ -2487,6 +2492,7 @@
return mHeadsUpManager.isHeadsUp(key);
}
+ @Override
protected boolean isSnoozedPackage(StatusBarNotification sbn) {
return mHeadsUpManager.isSnoozed(sbn.getPackageName());
}
@@ -2527,6 +2533,7 @@
* All changes to the status bar and notifications funnel through here and are batched.
*/
private class H extends BaseStatusBar.H {
+ @Override
public void handleMessage(Message m) {
super.handleMessage(m);
switch (m.what) {
@@ -2568,6 +2575,32 @@
mHeadsUpManager.releaseAllImmediately();
}
+ /**
+ * Called for system navigation gestures. First action opens the panel, second opens
+ * settings. Down action closes the entire panel.
+ */
+ @Override
+ public void handleSystemNavigationKey(int key) {
+ if (SPEW) Log.d(TAG, "handleSystemNavigationKey: " + key);
+ if (!panelsEnabled()) {
+ return;
+ }
+
+ // Panels are not available in setup
+ if (!mUserSetup) return;
+
+ if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP == key) {
+ mNotificationPanel.collapse(false /* delayed */, 1.0f /* speedUpFactor */);
+ } else if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN == key) {
+ if (mNotificationPanel.isFullyCollapsed()) {
+ mNotificationPanel.expand(true /* animate */);
+ } else if (!mNotificationPanel.isInSettings() && !mNotificationPanel.isExpanding()){
+ mNotificationPanel.flingSettings(0 /* velocity */, true /* expand */);
+ }
+ }
+
+ }
+
boolean panelsEnabled() {
return (mDisabled1 & StatusBarManager.DISABLE_EXPAND) == 0 && !ONLY_CORE_APPS;
}
@@ -2609,15 +2642,18 @@
mHandler.sendEmptyMessage(MSG_OPEN_SETTINGS_PANEL);
}
+ @Override
public void animateCollapsePanels(int flags) {
animateCollapsePanels(flags, false /* force */, false /* delayed */,
1.0f /* speedUpFactor */);
}
+ @Override
public void animateCollapsePanels(int flags, boolean force) {
animateCollapsePanels(flags, force, false /* delayed */, 1.0f /* speedUpFactor */);
}
+ @Override
public void animateCollapsePanels(int flags, boolean force, boolean delayed) {
animateCollapsePanels(flags, force, delayed, 1.0f /* speedUpFactor */);
}
@@ -3054,6 +3090,7 @@
}
}
+ @Override
public void topAppWindowChanged(boolean showMenu) {
if (SPEW) {
Log.d(TAG, (showMenu?"showing":"hiding") + " the MENU button");
@@ -3090,6 +3127,7 @@
+ ") " + v.getWidth() + "x" + v.getHeight() + "]";
}
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
synchronized (mQueueLock) {
pw.println("Current Status Bar state:");
@@ -3167,6 +3205,7 @@
pw.println("see the logcat for a dump of the views we have created.");
// must happen on ui thread
mHandler.post(new Runnable() {
+ @Override
public void run() {
mStatusBarView.getLocationOnScreen(mAbsPos);
Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
@@ -3277,6 +3316,7 @@
mContext, intent, mCurrentUserId);
final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
Runnable runnable = new Runnable() {
+ @Override
public void run() {
mAssistManager.hideAssist();
intent.setFlags(
@@ -3321,6 +3361,7 @@
@Override
public boolean onDismiss() {
AsyncTask.execute(new Runnable() {
+ @Override
public void run() {
try {
if (keyguardShowing && !afterKeyguardGone) {
@@ -3344,11 +3385,15 @@
}
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
public void onReceive(Context context, Intent intent) {
if (DEBUG) Log.v(TAG, "onReceive: " + intent);
String action = intent.getAction();
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
KeyboardShortcuts.dismiss();
+ if (mRemoteInputController != null) {
+ mRemoteInputController.closeRemoteInputs();
+ }
if (isCurrentProfile(getSendingUserId())) {
int flags = CommandQueue.FLAG_EXCLUDE_NONE;
String reason = intent.getStringExtra("reason");
@@ -3371,6 +3416,7 @@
};
private BroadcastReceiver mDemoReceiver = new BroadcastReceiver() {
+ @Override
public void onReceive(Context context, Intent intent) {
if (DEBUG) Log.v(TAG, "onReceive: " + intent);
String action = intent.getAction();
@@ -3630,6 +3676,7 @@
}
Runnable mStartTracing = new Runnable() {
+ @Override
public void run() {
vibrate();
SystemClock.sleep(250);
@@ -3640,6 +3687,7 @@
};
Runnable mStopTracing = new Runnable() {
+ @Override
public void run() {
android.os.Debug.stopMethodTracing();
Log.d(TAG, "stopTracing");
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 81c0d81..a13138d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -144,7 +144,7 @@
// listen for user / profile change.
try {
- ActivityManagerNative.getDefault().registerUserSwitchObserver(mUserSwitchListener);
+ ActivityManagerNative.getDefault().registerUserSwitchObserver(mUserSwitchListener, TAG);
} catch (RemoteException e) {
// Ignore
}
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 ae1e5d0..011ec22 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -30,6 +30,7 @@
import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.Secure;
+import android.service.quicksettings.Tile;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
@@ -403,10 +404,11 @@
String tileSpec = previousTiles.get(i);
if (!tileSpec.startsWith(CustomTile.PREFIX)) continue;
if (!newTiles.contains(tileSpec)) {
- Intent intent = new Intent().setComponent(
- CustomTile.getComponentFromSpec(tileSpec));
+ ComponentName component = CustomTile.getComponentFromSpec(tileSpec);
+ Intent intent = new Intent().setComponent(component);
TileLifecycleManager lifecycleManager = new TileLifecycleManager(new Handler(),
- mContext, intent, new UserHandle(ActivityManager.getCurrentUser()));
+ mContext, mServices, new Tile(component), intent,
+ new UserHandle(ActivityManager.getCurrentUser()));
lifecycleManager.onStopListening();
lifecycleManager.onTileRemoved();
lifecycleManager.flushMessagesAndUnbind();
@@ -416,10 +418,11 @@
String tileSpec = newTiles.get(i);
if (!tileSpec.startsWith(CustomTile.PREFIX)) continue;
if (!previousTiles.contains(tileSpec)) {
- Intent intent = new Intent().setComponent(
- CustomTile.getComponentFromSpec(tileSpec));
+ ComponentName component = CustomTile.getComponentFromSpec(tileSpec);
+ Intent intent = new Intent().setComponent(component);
TileLifecycleManager lifecycleManager = new TileLifecycleManager(new Handler(),
- mContext, intent, new UserHandle(ActivityManager.getCurrentUser()));
+ mContext, mServices, new Tile(component), intent,
+ new UserHandle(ActivityManager.getCurrentUser()));
lifecycleManager.onTileAdded();
lifecycleManager.flushMessagesAndUnbind();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
deleted file mode 100644
index 72eafd8..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ /dev/null
@@ -1,842 +0,0 @@
-/*
- * Copyright (C) 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
- */
-
-package com.android.systemui.statusbar.phone;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Outline;
-import android.graphics.Rect;
-import android.graphics.drawable.Animatable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.RippleDrawable;
-import android.util.AttributeSet;
-import android.util.MathUtils;
-import android.util.TypedValue;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
-import android.widget.Switch;
-import android.widget.TextView;
-import android.widget.Toast;
-import com.android.keyguard.KeyguardStatusView;
-import com.android.systemui.BatteryMeterView;
-import com.android.systemui.FontSizeUtils;
-import com.android.systemui.R;
-import com.android.systemui.qs.QSPanel;
-import com.android.systemui.qs.QSPanel.Callback;
-import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.QSTile.DetailAdapter;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
-import com.android.systemui.statusbar.policy.NextAlarmController;
-import com.android.systemui.statusbar.policy.UserInfoController;
-import com.android.systemui.tuner.TunerService;
-
-import java.text.NumberFormat;
-
-/**
- * The view to manage the header area in the expanded status bar.
- */
-public class StatusBarHeaderView extends BaseStatusBarHeader implements View.OnClickListener,
- BatteryController.BatteryStateChangeCallback, NextAlarmController.NextAlarmChangeCallback,
- EmergencyListener {
-
- private boolean mExpanded;
- private boolean mListening;
-
- private ViewGroup mSystemIconsContainer;
- private View mSystemIconsSuperContainer;
- private View mDateGroup;
- private View mClock;
- private TextView mTime;
- private TextView mAmPm;
- private MultiUserSwitch mMultiUserSwitch;
- private ImageView mMultiUserAvatar;
- private TextView mDateCollapsed;
- private TextView mDateExpanded;
- private LinearLayout mSystemIcons;
- private View mSignalCluster;
- private SettingsButton mSettingsButton;
- private View mSettingsContainer;
- private View mQsDetailHeader;
- private TextView mQsDetailHeaderTitle;
- private Switch mQsDetailHeaderSwitch;
- private ImageView mQsDetailHeaderProgress;
- private TextView mEmergencyCallsOnly;
- private TextView mBatteryLevel;
- private TextView mAlarmStatus;
-
- private boolean mShowEmergencyCallsOnly;
- private boolean mAlarmShowing;
- private AlarmManager.AlarmClockInfo mNextAlarm;
-
- private int mCollapsedHeight;
- private int mExpandedHeight;
-
- private int mMultiUserExpandedMargin;
- private int mMultiUserCollapsedMargin;
-
- private int mClockMarginBottomExpanded;
- private int mClockMarginBottomCollapsed;
- private int mMultiUserSwitchWidthCollapsed;
- private int mMultiUserSwitchWidthExpanded;
-
- private int mClockCollapsedSize;
- private int mClockExpandedSize;
-
- /**
- * In collapsed QS, the clock and avatar are scaled down a bit post-layout to allow for a nice
- * transition. These values determine that factor.
- */
- private float mClockCollapsedScaleFactor;
- private float mAvatarCollapsedScaleFactor;
-
- private ActivityStarter mActivityStarter;
- private BatteryController mBatteryController;
- private NextAlarmController mNextAlarmController;
- private QSPanel mQSPanel;
-
- private final Rect mClipBounds = new Rect();
-
- private boolean mCaptureValues;
- private boolean mSignalClusterDetached;
- private final LayoutValues mCollapsedValues = new LayoutValues();
- private final LayoutValues mExpandedValues = new LayoutValues();
- private final LayoutValues mCurrentValues = new LayoutValues();
-
- private float mCurrentT;
- private boolean mShowingDetail;
- private boolean mDetailTransitioning;
-
- private boolean mAllowExpand = true;
-
- public StatusBarHeaderView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mSystemIconsSuperContainer = findViewById(R.id.system_icons_super_container);
- mSystemIconsContainer = (ViewGroup) findViewById(R.id.system_icons_container);
- mSystemIconsSuperContainer.setOnClickListener(this);
- mDateGroup = findViewById(R.id.date_group);
- mClock = findViewById(R.id.clock);
- mTime = (TextView) findViewById(R.id.time_view);
- mAmPm = (TextView) findViewById(R.id.am_pm_view);
- mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch);
- mMultiUserAvatar = (ImageView) findViewById(R.id.multi_user_avatar);
- mDateCollapsed = (TextView) findViewById(R.id.date_collapsed);
- mDateExpanded = (TextView) findViewById(R.id.date_expanded);
- mSettingsButton = (SettingsButton) findViewById(R.id.settings_button);
- mSettingsContainer = findViewById(R.id.settings_button_container);
- mSettingsButton.setOnClickListener(this);
- mQsDetailHeader = findViewById(R.id.qs_detail_header);
- mQsDetailHeader.setAlpha(0);
- mQsDetailHeaderTitle = (TextView) mQsDetailHeader.findViewById(android.R.id.title);
- mQsDetailHeaderSwitch = (Switch) mQsDetailHeader.findViewById(android.R.id.toggle);
- mQsDetailHeaderProgress = (ImageView) findViewById(R.id.qs_detail_header_progress);
- mEmergencyCallsOnly = (TextView) findViewById(R.id.header_emergency_calls_only);
- mBatteryLevel = (TextView) findViewById(R.id.battery_level);
- mAlarmStatus = (TextView) findViewById(R.id.alarm_status);
- mAlarmStatus.setOnClickListener(this);
- mSignalCluster = findViewById(R.id.signal_cluster);
- mSystemIcons = (LinearLayout) findViewById(R.id.system_icons);
- loadDimens();
- updateVisibilities();
- updateClockScale();
- updateAvatarScale();
- addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right,
- int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
- if ((right - left) != (oldRight - oldLeft)) {
- // width changed, update clipping
- setClipping(getHeight());
- }
- boolean rtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
- mTime.setPivotX(rtl ? mTime.getWidth() : 0);
- mTime.setPivotY(mTime.getBaseline());
- updateAmPmTranslation();
- }
- });
- setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- outline.setRect(mClipBounds);
- }
- });
- requestCaptureValues();
-
- // RenderThread is doing more harm than good when touching the header (to expand quick
- // settings), so disable it for this view
- ((RippleDrawable) getBackground()).setForceSoftware(true);
- ((RippleDrawable) mSettingsButton.getBackground()).setForceSoftware(true);
- ((RippleDrawable) mSystemIconsSuperContainer.getBackground()).setForceSoftware(true);
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
- if (mCaptureValues) {
- if (mExpanded) {
- captureLayoutValues(mExpandedValues);
- } else {
- captureLayoutValues(mCollapsedValues);
- }
- mCaptureValues = false;
- updateLayoutValues(mCurrentT);
- }
- mAlarmStatus.setX(mDateGroup.getLeft() + mDateCollapsed.getRight());
- }
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- FontSizeUtils.updateFontSize(mBatteryLevel, R.dimen.battery_level_text_size);
- FontSizeUtils.updateFontSize(mEmergencyCallsOnly,
- R.dimen.qs_emergency_calls_only_text_size);
- FontSizeUtils.updateFontSize(mDateCollapsed, R.dimen.qs_date_collapsed_size);
- FontSizeUtils.updateFontSize(mDateExpanded, R.dimen.qs_date_collapsed_size);
- FontSizeUtils.updateFontSize(mAlarmStatus, R.dimen.qs_date_collapsed_size);
- FontSizeUtils.updateFontSize(this, android.R.id.title, R.dimen.qs_detail_header_text_size);
- FontSizeUtils.updateFontSize(this, android.R.id.toggle, R.dimen.qs_detail_header_text_size);
- FontSizeUtils.updateFontSize(mAmPm, R.dimen.qs_time_collapsed_size);
- FontSizeUtils.updateFontSize(this, R.id.empty_time_view, R.dimen.qs_time_expanded_size);
-
- mEmergencyCallsOnly.setText(com.android.internal.R.string.emergency_calls_only);
-
- mClockCollapsedSize = getResources().getDimensionPixelSize(R.dimen.qs_time_collapsed_size);
- mClockExpandedSize = getResources().getDimensionPixelSize(R.dimen.qs_time_expanded_size);
- mClockCollapsedScaleFactor = (float) mClockCollapsedSize / (float) mClockExpandedSize;
-
- updateClockScale();
- updateClockCollapsedMargin();
- }
-
- private void updateClockCollapsedMargin() {
- Resources res = getResources();
- int padding = res.getDimensionPixelSize(R.dimen.clock_collapsed_bottom_margin);
- int largePadding = res.getDimensionPixelSize(
- R.dimen.clock_collapsed_bottom_margin_large_text);
- float largeFactor = (MathUtils.constrain(getResources().getConfiguration().fontScale, 1.0f,
- FontSizeUtils.LARGE_TEXT_SCALE) - 1f) / (FontSizeUtils.LARGE_TEXT_SCALE - 1f);
- mClockMarginBottomCollapsed = Math.round((1 - largeFactor) * padding + largeFactor * largePadding);
- requestLayout();
- }
-
- private void requestCaptureValues() {
- mCaptureValues = true;
- requestLayout();
- }
-
- private void loadDimens() {
- mCollapsedHeight = getResources().getDimensionPixelSize(R.dimen.status_bar_header_height);
- mExpandedHeight = getResources().getDimensionPixelSize(
- R.dimen.status_bar_header_height_expanded);
- mMultiUserExpandedMargin =
- getResources().getDimensionPixelSize(R.dimen.multi_user_switch_expanded_margin);
- mMultiUserCollapsedMargin =
- getResources().getDimensionPixelSize(R.dimen.multi_user_switch_collapsed_margin);
- mClockMarginBottomExpanded =
- getResources().getDimensionPixelSize(R.dimen.clock_expanded_bottom_margin);
- updateClockCollapsedMargin();
- mMultiUserSwitchWidthCollapsed =
- getResources().getDimensionPixelSize(R.dimen.multi_user_switch_width_collapsed);
- mMultiUserSwitchWidthExpanded =
- getResources().getDimensionPixelSize(R.dimen.multi_user_switch_width_expanded);
- mAvatarCollapsedScaleFactor =
- getResources().getDimensionPixelSize(R.dimen.multi_user_avatar_collapsed_size)
- / (float) mMultiUserAvatar.getLayoutParams().width;
- mClockCollapsedSize = getResources().getDimensionPixelSize(R.dimen.qs_time_collapsed_size);
- mClockExpandedSize = getResources().getDimensionPixelSize(R.dimen.qs_time_expanded_size);
- mClockCollapsedScaleFactor = (float) mClockCollapsedSize / (float) mClockExpandedSize;
-
- }
-
- public void setActivityStarter(ActivityStarter activityStarter) {
- mActivityStarter = activityStarter;
- }
-
- public void setBatteryController(BatteryController batteryController) {
- mBatteryController = batteryController;
- ((BatteryMeterView) findViewById(R.id.battery)).setBatteryController(batteryController);
- }
-
- public void setNextAlarmController(NextAlarmController nextAlarmController) {
- mNextAlarmController = nextAlarmController;
- }
-
- public int getCollapsedHeight() {
- return mCollapsedHeight;
- }
-
- public int getExpandedHeight() {
- return mAllowExpand ? mExpandedHeight : mCollapsedHeight;
- }
-
- public void setListening(boolean listening) {
- if (listening == mListening) {
- return;
- }
- mListening = listening;
- updateListeners();
- }
-
- public void setExpanded(boolean expanded) {
- if (!mAllowExpand) {
- expanded = false;
- }
- boolean changed = expanded != mExpanded;
- mExpanded = expanded;
- if (changed) {
- updateEverything();
- }
- }
-
- public void updateEverything() {
- updateHeights();
- updateVisibilities();
- updateSystemIconsLayoutParams();
- updateClickTargets();
- updateMultiUserSwitch();
- updateClockScale();
- updateAvatarScale();
- updateClockLp();
- requestCaptureValues();
- }
-
- private void updateHeights() {
- int height = mExpanded ? mExpandedHeight : mCollapsedHeight;
- ViewGroup.LayoutParams lp = getLayoutParams();
- if (lp.height != height) {
- lp.height = height;
- setLayoutParams(lp);
- }
- }
-
- private void updateVisibilities() {
- mDateCollapsed.setVisibility(mExpanded && mAlarmShowing ? View.VISIBLE : View.INVISIBLE);
- mDateExpanded.setVisibility(mExpanded && mAlarmShowing ? View.INVISIBLE : View.VISIBLE);
- mAlarmStatus.setVisibility(mExpanded && mAlarmShowing ? View.VISIBLE : View.INVISIBLE);
- mSettingsContainer.setVisibility(mExpanded ? View.VISIBLE : View.INVISIBLE);
- mQsDetailHeader.setVisibility(mExpanded && mShowingDetail? View.VISIBLE : View.INVISIBLE);
- if (mSignalCluster != null) {
- updateSignalClusterDetachment();
- }
- mEmergencyCallsOnly.setVisibility(mExpanded && mShowEmergencyCallsOnly ? VISIBLE : GONE);
- mBatteryLevel.setVisibility(mExpanded ? View.VISIBLE : View.GONE);
- mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility(
- TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE);
- }
-
- private void updateSignalClusterDetachment() {
- boolean detached = mExpanded;
- if (detached != mSignalClusterDetached) {
- if (detached) {
- getOverlay().add(mSignalCluster);
- } else {
- reattachSignalCluster();
- }
- }
- mSignalClusterDetached = detached;
- }
-
- private void reattachSignalCluster() {
- getOverlay().remove(mSignalCluster);
- mSystemIcons.addView(mSignalCluster, 1);
- }
-
- private void updateSystemIconsLayoutParams() {
- RelativeLayout.LayoutParams lp = (LayoutParams) mSystemIconsSuperContainer.getLayoutParams();
- int rule = mExpanded
- ? mSettingsContainer.getId()
- : mMultiUserSwitch.getId();
- if (rule != lp.getRules()[RelativeLayout.START_OF]) {
- lp.addRule(RelativeLayout.START_OF, rule);
- mSystemIconsSuperContainer.setLayoutParams(lp);
- }
- }
-
- private void updateListeners() {
- if (mListening) {
- mBatteryController.addStateChangedCallback(this);
- mNextAlarmController.addStateChangedCallback(this);
- } else {
- mBatteryController.removeStateChangedCallback(this);
- mNextAlarmController.removeStateChangedCallback(this);
- }
- }
-
- private void updateAvatarScale() {
- if (mExpanded) {
- mMultiUserAvatar.setScaleX(1f);
- mMultiUserAvatar.setScaleY(1f);
- } else {
- mMultiUserAvatar.setScaleX(mAvatarCollapsedScaleFactor);
- mMultiUserAvatar.setScaleY(mAvatarCollapsedScaleFactor);
- }
- }
-
- private void updateClockScale() {
- mTime.setTextSize(TypedValue.COMPLEX_UNIT_PX, mExpanded
- ? mClockExpandedSize
- : mClockCollapsedSize);
- mTime.setScaleX(1f);
- mTime.setScaleY(1f);
- updateAmPmTranslation();
- }
-
- private void updateAmPmTranslation() {
- boolean rtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
- mAmPm.setTranslationX((rtl ? 1 : -1) * mTime.getWidth() * (1 - mTime.getScaleX()));
- }
-
- @Override
- public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
- String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
- mBatteryLevel.setText(percentage);
- }
-
- @Override
- public void onPowerSaveChanged(boolean isPowerSave) {
- // could not care less
- }
-
- @Override
- public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
- mNextAlarm = nextAlarm;
- if (nextAlarm != null) {
- mAlarmStatus.setText(KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm));
- }
- mAlarmShowing = nextAlarm != null;
- updateEverything();
- requestCaptureValues();
- }
-
- private void updateClickTargets() {
- mMultiUserSwitch.setClickable(mExpanded);
- mMultiUserSwitch.setFocusable(mExpanded);
- mSystemIconsSuperContainer.setClickable(mExpanded);
- mSystemIconsSuperContainer.setFocusable(mExpanded);
- mAlarmStatus.setClickable(mNextAlarm != null && mNextAlarm.getShowIntent() != null);
- }
-
- private void updateClockLp() {
- int marginBottom = mExpanded
- ? mClockMarginBottomExpanded
- : mClockMarginBottomCollapsed;
- LayoutParams lp = (LayoutParams) mDateGroup.getLayoutParams();
- if (marginBottom != lp.bottomMargin) {
- lp.bottomMargin = marginBottom;
- mDateGroup.setLayoutParams(lp);
- }
- }
-
- private void updateMultiUserSwitch() {
- int marginEnd;
- int width;
- if (mExpanded) {
- marginEnd = mMultiUserExpandedMargin;
- width = mMultiUserSwitchWidthExpanded;
- } else {
- marginEnd = mMultiUserCollapsedMargin;
- width = mMultiUserSwitchWidthCollapsed;
- }
- MarginLayoutParams lp = (MarginLayoutParams) mMultiUserSwitch.getLayoutParams();
- if (marginEnd != lp.getMarginEnd() || lp.width != width) {
- lp.setMarginEnd(marginEnd);
- lp.width = width;
- mMultiUserSwitch.setLayoutParams(lp);
- }
- }
-
- public void setExpansion(float t) {
- if (!mExpanded) {
- t = 0f;
- }
- mCurrentT = t;
- float height = mCollapsedHeight + t * (mExpandedHeight - mCollapsedHeight);
- if (height < mCollapsedHeight) {
- height = mCollapsedHeight;
- }
- if (height > mExpandedHeight) {
- height = mExpandedHeight;
- }
- setClipping(height);
- updateLayoutValues(t);
- }
-
- private void updateLayoutValues(float t) {
- if (mCaptureValues) {
- return;
- }
- mCurrentValues.interpoloate(mCollapsedValues, mExpandedValues, t);
- applyLayoutValues(mCurrentValues);
- }
-
- private void setClipping(float height) {
- mClipBounds.set(getPaddingLeft(), 0, getWidth() - getPaddingRight(), (int) height);
- setClipBounds(mClipBounds);
- invalidateOutline();
- }
-
- public void setUserInfoController(UserInfoController userInfoController) {
- userInfoController.addListener(new UserInfoController.OnUserInfoChangedListener() {
- @Override
- public void onUserInfoChanged(String name, Drawable picture) {
- mMultiUserAvatar.setImageDrawable(picture);
- }
- });
- }
-
- @Override
- public void setCallback(Callback qsPanelCallback) {
- }
-
- @Override
- public void onClick(View v) {
- if (v == mSettingsButton) {
- if (mSettingsButton.isTunerClick()) {
- if (TunerService.isTunerEnabled(mContext)) {
- TunerService.showResetRequest(mContext, new Runnable() {
- @Override
- public void run() {
- // Relaunch settings so that the tuner disappears.
- startSettingsActivity();
- }
- });
- } else {
- Toast.makeText(getContext(), R.string.tuner_toast, Toast.LENGTH_LONG).show();
- TunerService.setTunerEnabled(mContext, true);
- }
- }
- startSettingsActivity();
- } else if (v == mSystemIconsSuperContainer) {
- startBatteryActivity();
- } else if (v == mAlarmStatus && mNextAlarm != null) {
- PendingIntent showIntent = mNextAlarm.getShowIntent();
- if (showIntent != null) {
- mActivityStarter.startPendingIntentDismissingKeyguard(showIntent);
- }
- }
- }
-
- private void startSettingsActivity() {
- mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS),
- true /* dismissShade */);
- }
-
- private void startBatteryActivity() {
- mActivityStarter.startActivity(new Intent(Intent.ACTION_POWER_USAGE_SUMMARY),
- true /* dismissShade */);
- }
-
- public void setQSPanel(QSPanel qsp) {
- mQSPanel = qsp;
- if (mQSPanel != null) {
- mQSPanel.setCallback(mQsPanelCallback);
- }
- mMultiUserSwitch.setQsPanel(qsp);
- }
-
- @Override
- public boolean shouldDelayChildPressedState() {
- return true;
- }
-
- @Override
- public void setEmergencyCallsOnly(boolean show) {
- boolean changed = show != mShowEmergencyCallsOnly;
- if (changed) {
- mShowEmergencyCallsOnly = show;
- if (mExpanded) {
- updateEverything();
- requestCaptureValues();
- }
- }
- }
-
- @Override
- protected void dispatchSetPressed(boolean pressed) {
- // We don't want that everything lights up when we click on the header, so block the request
- // here.
- }
-
- private void captureLayoutValues(LayoutValues target) {
- target.timeScale = mExpanded ? 1f : mClockCollapsedScaleFactor;
- target.clockY = mClock.getBottom();
- target.dateY = mDateGroup.getTop();
- target.emergencyCallsOnlyAlpha = getAlphaForVisibility(mEmergencyCallsOnly);
- target.alarmStatusAlpha = getAlphaForVisibility(mAlarmStatus);
- target.dateCollapsedAlpha = getAlphaForVisibility(mDateCollapsed);
- target.dateExpandedAlpha = getAlphaForVisibility(mDateExpanded);
- target.avatarScale = mMultiUserAvatar.getScaleX();
- target.avatarX = mMultiUserSwitch.getLeft() + mMultiUserAvatar.getLeft();
- target.avatarY = mMultiUserSwitch.getTop() + mMultiUserAvatar.getTop();
- if (getLayoutDirection() == LAYOUT_DIRECTION_LTR) {
- target.batteryX = mSystemIconsSuperContainer.getLeft()
- + mSystemIconsContainer.getRight();
- } else {
- target.batteryX = mSystemIconsSuperContainer.getLeft()
- + mSystemIconsContainer.getLeft();
- }
- target.batteryY = mSystemIconsSuperContainer.getTop() + mSystemIconsContainer.getTop();
- target.batteryLevelAlpha = getAlphaForVisibility(mBatteryLevel);
- target.settingsAlpha = getAlphaForVisibility(mSettingsContainer);
- target.settingsTranslation = mExpanded
- ? 0
- : mMultiUserSwitch.getLeft() - mSettingsContainer.getLeft();
- target.signalClusterAlpha = mSignalClusterDetached ? 0f : 1f;
- target.settingsRotation = !mExpanded ? 90f : 0f;
- }
-
- private float getAlphaForVisibility(View v) {
- return v == null || v.getVisibility() == View.VISIBLE ? 1f : 0f;
- }
-
- private void applyAlpha(View v, float alpha) {
- if (v == null || v.getVisibility() == View.GONE) {
- return;
- }
- if (alpha == 0f) {
- v.setVisibility(View.INVISIBLE);
- } else {
- v.setVisibility(View.VISIBLE);
- v.setAlpha(alpha);
- }
- }
-
- private void applyLayoutValues(LayoutValues values) {
- mTime.setScaleX(values.timeScale);
- mTime.setScaleY(values.timeScale);
- mClock.setY(values.clockY - mClock.getHeight());
- mDateGroup.setY(values.dateY);
- mAlarmStatus.setY(values.dateY - mAlarmStatus.getPaddingTop());
- mMultiUserAvatar.setScaleX(values.avatarScale);
- mMultiUserAvatar.setScaleY(values.avatarScale);
- mMultiUserAvatar.setX(values.avatarX - mMultiUserSwitch.getLeft());
- mMultiUserAvatar.setY(values.avatarY - mMultiUserSwitch.getTop());
- if (getLayoutDirection() == LAYOUT_DIRECTION_LTR) {
- mSystemIconsSuperContainer.setX(values.batteryX - mSystemIconsContainer.getRight());
- } else {
- mSystemIconsSuperContainer.setX(values.batteryX - mSystemIconsContainer.getLeft());
- }
- mSystemIconsSuperContainer.setY(values.batteryY - mSystemIconsContainer.getTop());
- if (mSignalCluster != null && mExpanded) {
- if (getLayoutDirection() == LAYOUT_DIRECTION_LTR) {
- mSignalCluster.setX(mSystemIconsSuperContainer.getX()
- - mSignalCluster.getWidth());
- } else {
- mSignalCluster.setX(mSystemIconsSuperContainer.getX()
- + mSystemIconsSuperContainer.getWidth());
- }
- mSignalCluster.setY(
- mSystemIconsSuperContainer.getY() + mSystemIconsSuperContainer.getHeight()/2
- - mSignalCluster.getHeight()/2);
- } else if (mSignalCluster != null) {
- mSignalCluster.setTranslationX(0f);
- mSignalCluster.setTranslationY(0f);
- }
- if (!mSettingsButton.isAnimating()) {
- mSettingsContainer.setTranslationY(mSystemIconsSuperContainer.getTranslationY());
- mSettingsContainer.setTranslationX(values.settingsTranslation);
- mSettingsButton.setRotation(values.settingsRotation);
- }
- applyAlpha(mEmergencyCallsOnly, values.emergencyCallsOnlyAlpha);
- if (!mShowingDetail && !mDetailTransitioning) {
- // Otherwise it needs to stay invisible
- applyAlpha(mAlarmStatus, values.alarmStatusAlpha);
- }
- applyAlpha(mDateCollapsed, values.dateCollapsedAlpha);
- applyAlpha(mDateExpanded, values.dateExpandedAlpha);
- applyAlpha(mBatteryLevel, values.batteryLevelAlpha);
- applyAlpha(mSettingsContainer, values.settingsAlpha);
- applyAlpha(mSignalCluster, values.signalClusterAlpha);
- if (!mExpanded) {
- mTime.setScaleX(1f);
- mTime.setScaleY(1f);
- }
- updateAmPmTranslation();
- }
-
- /**
- * Captures all layout values (position, visibility) for a certain state. This is used for
- * animations.
- */
- private static final class LayoutValues {
-
- float dateExpandedAlpha;
- float dateCollapsedAlpha;
- float emergencyCallsOnlyAlpha;
- float alarmStatusAlpha;
- float timeScale = 1f;
- float clockY;
- float dateY;
- float avatarScale;
- float avatarX;
- float avatarY;
- float batteryX;
- float batteryY;
- float batteryLevelAlpha;
- float settingsAlpha;
- float settingsTranslation;
- float signalClusterAlpha;
- float settingsRotation;
-
- public void interpoloate(LayoutValues v1, LayoutValues v2, float t) {
- timeScale = v1.timeScale * (1 - t) + v2.timeScale * t;
- clockY = v1.clockY * (1 - t) + v2.clockY * t;
- dateY = v1.dateY * (1 - t) + v2.dateY * t;
- avatarScale = v1.avatarScale * (1 - t) + v2.avatarScale * t;
- avatarX = v1.avatarX * (1 - t) + v2.avatarX * t;
- avatarY = v1.avatarY * (1 - t) + v2.avatarY * t;
- batteryX = v1.batteryX * (1 - t) + v2.batteryX * t;
- batteryY = v1.batteryY * (1 - t) + v2.batteryY * t;
- settingsTranslation = v1.settingsTranslation * (1 - t) + v2.settingsTranslation * t;
-
- float t1 = Math.max(0, t - 0.5f) * 2;
- settingsRotation = v1.settingsRotation * (1 - t1) + v2.settingsRotation * t1;
- emergencyCallsOnlyAlpha =
- v1.emergencyCallsOnlyAlpha * (1 - t1) + v2.emergencyCallsOnlyAlpha * t1;
-
- float t2 = Math.min(1, 2 * t);
- signalClusterAlpha = v1.signalClusterAlpha * (1 - t2) + v2.signalClusterAlpha * t2;
-
- float t3 = Math.max(0, t - 0.7f) / 0.3f;
- batteryLevelAlpha = v1.batteryLevelAlpha * (1 - t3) + v2.batteryLevelAlpha * t3;
- settingsAlpha = v1.settingsAlpha * (1 - t3) + v2.settingsAlpha * t3;
- dateExpandedAlpha = v1.dateExpandedAlpha * (1 - t3) + v2.dateExpandedAlpha * t3;
- dateCollapsedAlpha = v1.dateCollapsedAlpha * (1 - t3) + v2.dateCollapsedAlpha * t3;
- alarmStatusAlpha = v1.alarmStatusAlpha * (1 - t3) + v2.alarmStatusAlpha * t3;
- }
- }
-
- private final QSPanel.Callback mQsPanelCallback = new QSPanel.Callback() {
- private boolean mScanState;
-
- @Override
- public void onToggleStateChanged(final boolean state) {
- post(new Runnable() {
- @Override
- public void run() {
- handleToggleStateChanged(state);
- }
- });
- }
-
- @Override
- public void onShowingDetail(final DetailAdapter detail, int x, int y) {
- mDetailTransitioning = true;
- post(new Runnable() {
- @Override
- public void run() {
- handleShowingDetail(detail);
- }
- });
- }
-
- @Override
- public void onScanStateChanged(final boolean state) {
- post(new Runnable() {
- @Override
- public void run() {
- handleScanStateChanged(state);
- }
- });
- }
-
- private void handleToggleStateChanged(boolean state) {
- mQsDetailHeaderSwitch.setChecked(state);
- }
-
- private void handleScanStateChanged(boolean state) {
- if (mScanState == state) return;
- mScanState = state;
- final Animatable anim = (Animatable) mQsDetailHeaderProgress.getDrawable();
- if (state) {
- mQsDetailHeaderProgress.animate().alpha(1f);
- anim.start();
- } else {
- mQsDetailHeaderProgress.animate().alpha(0f);
- anim.stop();
- }
- }
-
- private void handleShowingDetail(final QSTile.DetailAdapter detail) {
- final boolean showingDetail = detail != null;
- transition(mClock, !showingDetail);
- transition(mDateGroup, !showingDetail);
- if (mAlarmShowing) {
- transition(mAlarmStatus, !showingDetail);
- }
- transition(mQsDetailHeader, showingDetail);
- mShowingDetail = showingDetail;
- if (showingDetail) {
- mQsDetailHeaderTitle.setText(detail.getTitle());
- final Boolean toggleState = detail.getToggleState();
- if (toggleState == null) {
- mQsDetailHeaderSwitch.setVisibility(INVISIBLE);
- mQsDetailHeader.setClickable(false);
- } else {
- mQsDetailHeaderSwitch.setVisibility(VISIBLE);
- mQsDetailHeaderSwitch.setChecked(toggleState);
- mQsDetailHeader.setClickable(true);
- mQsDetailHeader.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- boolean checked = !mQsDetailHeaderSwitch.isChecked();
- mQsDetailHeaderSwitch.setChecked(checked);
- detail.setToggleState(checked);
- }
- });
- }
- } else {
- mQsDetailHeader.setClickable(false);
- }
- }
-
- private void transition(final View v, final boolean in) {
- if (in) {
- v.bringToFront();
- v.setVisibility(VISIBLE);
- }
- if (v.hasOverlappingRendering()) {
- v.animate().withLayer();
- }
- v.animate()
- .alpha(in ? 1 : 0)
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- if (!in) {
- v.setVisibility(INVISIBLE);
- }
- mDetailTransitioning = false;
- }
- })
- .start();
- }
- };
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 6439bea..014cc49 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -40,7 +40,6 @@
private static final String TAG = "BluetoothController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
private final LocalBluetoothManager mLocalBluetoothManager;
private final UserManager mUserManager;
private final int mCurrentUser;
@@ -78,7 +77,7 @@
pw.print(" mEnabled="); pw.println(mEnabled);
pw.print(" mConnectionState="); pw.println(stateToString(mConnectionState));
pw.print(" mLastDevice="); pw.println(mLastDevice);
- pw.print(" mCallbacks.size="); pw.println(mCallbacks.size());
+ pw.print(" mCallbacks.size="); pw.println(mHandler.mCallbacks.size());
pw.println(" Bluetooth Devices:");
for (CachedBluetoothDevice device :
mLocalBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy()) {
@@ -106,13 +105,13 @@
@Override
public void addStateChangedCallback(Callback cb) {
- mCallbacks.add(cb);
+ mHandler.obtainMessage(H.MSG_ADD_CALLBACK, cb).sendToTarget();
mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
}
@Override
public void removeStateChangedCallback(Callback cb) {
- mCallbacks.remove(cb);
+ mHandler.obtainMessage(H.MSG_REMOVE_CALLBACK, cb).sendToTarget();
}
@Override
@@ -236,8 +235,12 @@
}
private final class H extends Handler {
+ private final ArrayList<BluetoothController.Callback> mCallbacks = new ArrayList<>();
+
private static final int MSG_PAIRED_DEVICES_CHANGED = 1;
private static final int MSG_STATE_CHANGED = 2;
+ private static final int MSG_ADD_CALLBACK = 3;
+ private static final int MSG_REMOVE_CALLBACK = 4;
@Override
public void handleMessage(Message msg) {
@@ -248,6 +251,12 @@
case MSG_STATE_CHANGED:
fireStateChange();
break;
+ case MSG_ADD_CALLBACK:
+ mCallbacks.add((BluetoothController.Callback) msg.obj);
+ break;
+ case MSG_REMOVE_CALLBACK:
+ mCallbacks.remove((BluetoothController.Callback) msg.obj);
+ break;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 9041341..4664851 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -16,12 +16,14 @@
package com.android.systemui.statusbar.policy;
+import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
+import android.os.UserManager;
import android.util.Log;
import java.io.FileDescriptor;
@@ -49,7 +51,8 @@
@Override
public boolean isHotspotSupported() {
return mConnectivityManager.isTetheringSupported()
- && mConnectivityManager.getTetherableWifiRegexs().length != 0;
+ && mConnectivityManager.getTetherableWifiRegexs().length != 0
+ && UserManager.get(mContext).isUserAdmin(ActivityManager.getCurrentUser());
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 83e25eb..ac3246d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -197,8 +197,11 @@
if (mConfig.show4gForLte) {
mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.FOUR_G);
+ mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
+ TelephonyIcons.FOUR_G_PLUS);
} else {
mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.LTE);
+ mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA, TelephonyIcons.LTE);
}
mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_IWLAN, TelephonyIcons.WFC);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index b27bfcb..7a042af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -781,6 +781,7 @@
datatype.equals("1x") ? TelephonyIcons.ONE_X :
datatype.equals("3g") ? TelephonyIcons.THREE_G :
datatype.equals("4g") ? TelephonyIcons.FOUR_G :
+ datatype.equals("4g+") ? TelephonyIcons.FOUR_G_PLUS :
datatype.equals("e") ? TelephonyIcons.E :
datatype.equals("g") ? TelephonyIcons.G :
datatype.equals("h") ? TelephonyIcons.H :
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 7704a07..a2289c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -21,6 +21,7 @@
import android.app.RemoteInput;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ShortcutManager;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -132,6 +133,15 @@
mEditText.mShowImeOnInputConnection = false;
mController.remoteInputSent(mEntry);
+ // Tell ShortcutManager that this package has been "activated". ShortcutManager
+ // will reset the throttling for this package.
+ // Strictly speaking, the intent receiver may be different from the notification publisher,
+ // but that's an edge case, and also because we can't always know which package will receive
+ // an intent, so we just reset for the publisher.
+ getContext().getSystemService(ShortcutManager.class).onApplicationActive(
+ mEntry.notification.getPackageName(),
+ mEntry.notification.getUser().getIdentifier());
+
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_SEND,
mEntry.notification.getPackageName());
try {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
index 6ff8f77..d91b332 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -182,6 +182,19 @@
static final int QS_DATA_4G = R.drawable.ic_qs_signal_4g;
+ static final int[][] DATA_4G_PLUS = {
+ { R.drawable.stat_sys_data_fully_connected_4g_plus,
+ R.drawable.stat_sys_data_fully_connected_4g_plus,
+ R.drawable.stat_sys_data_fully_connected_4g_plus,
+ R.drawable.stat_sys_data_fully_connected_4g_plus },
+ { R.drawable.stat_sys_data_fully_connected_4g_plus,
+ R.drawable.stat_sys_data_fully_connected_4g_plus,
+ R.drawable.stat_sys_data_fully_connected_4g_plus,
+ R.drawable.stat_sys_data_fully_connected_4g_plus }
+ };
+
+ static final int QS_DATA_4G_PLUS = R.drawable.ic_qs_signal_4g_plus;
+
// LTE branded "LTE"
static final int[][] DATA_LTE = {
{ R.drawable.stat_sys_data_fully_connected_lte,
@@ -204,6 +217,7 @@
static final int ICON_H = R.drawable.stat_sys_data_fully_connected_h;
static final int ICON_3G = R.drawable.stat_sys_data_fully_connected_3g;
static final int ICON_4G = R.drawable.stat_sys_data_fully_connected_4g;
+ static final int ICON_4G_PLUS = R.drawable.stat_sys_data_fully_connected_4g_plus;
static final int ICON_1X = R.drawable.stat_sys_data_fully_connected_1x;
static final int ICON_CARRIER_NETWORK_CHANGE =
R.drawable.stat_sys_signal_carrier_network_change_animation;
@@ -213,6 +227,7 @@
static final int QS_ICON_LTE = R.drawable.ic_qs_signal_lte;
static final int QS_ICON_3G = R.drawable.ic_qs_signal_3g;
static final int QS_ICON_4G = R.drawable.ic_qs_signal_4g;
+ static final int QS_ICON_4G_PLUS = R.drawable.ic_qs_signal_4g_plus;
static final int QS_ICON_1X = R.drawable.ic_qs_signal_1x;
static final int QS_ICON_CARRIER_NETWORK_CHANGE =
R.drawable.ic_qs_signal_carrier_network_change_animation;
@@ -348,6 +363,21 @@
TelephonyIcons.QS_DATA_4G
);
+ static final MobileIconGroup FOUR_G_PLUS = new MobileIconGroup(
+ "4G+",
+ TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
+ TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+ AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+ 0,0,
+ TelephonyIcons.TELEPHONY_NO_NETWORK,
+ TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+ AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+ R.string.accessibility_data_connection_4g_plus,
+ TelephonyIcons.ICON_4G_PLUS,
+ true,
+ TelephonyIcons.QS_DATA_4G_PLUS
+ );
+
static final MobileIconGroup LTE = new MobileIconGroup(
"LTE",
TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 415b7a1..379ad53 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -51,6 +51,7 @@
import com.android.settingslib.RestrictedLockUtils;
import com.android.systemui.GuestResumeSessionReceiver;
import com.android.systemui.R;
+import com.android.systemui.SystemUI;
import com.android.systemui.SystemUISecondaryUserService;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.tiles.UserDetailView;
@@ -380,6 +381,18 @@
Log.e(TAG, "Couldn't switch to user, id=" + userId);
}
+ public int getSwitchableUserCount() {
+ int count = 0;
+ final int N = mUsers.size();
+ for (int i = 0; i < N; ++i) {
+ UserRecord record = mUsers.get(i);
+ if (record.info != null && record.info.supportsSwitchTo()) {
+ count++;
+ }
+ }
+ return count;
+ }
+
private void switchToUserId(int id) {
try {
pauseRefreshUsers();
@@ -523,7 +536,7 @@
private void showLogoutNotification(int userId) {
PendingIntent logoutPI = PendingIntent.getBroadcastAsUser(mContext,
0, new Intent(ACTION_LOGOUT_USER), 0, UserHandle.SYSTEM);
- Notification notification = new Notification.Builder(mContext)
+ Notification.Builder builder = new Notification.Builder(mContext)
.setVisibility(Notification.VISIBILITY_SECRET)
.setPriority(Notification.PRIORITY_MIN)
.setSmallIcon(R.drawable.ic_person)
@@ -534,10 +547,10 @@
.setShowWhen(false)
.addAction(R.drawable.ic_delete,
mContext.getString(R.string.user_logout_notification_action),
- logoutPI)
- .build();
+ logoutPI);
+ SystemUI.overrideNotificationAppName(mContext, builder);
NotificationManager.from(mContext).notifyAsUser(TAG_LOGOUT_USER, ID_LOGOUT_USER,
- notification, new UserHandle(userId));
+ builder.build(), new UserHandle(userId));
}
};
@@ -547,7 +560,7 @@
PendingIntent removeGuestPI = canSwitchUsers ? PendingIntent.getBroadcastAsUser(mContext,
0, new Intent(ACTION_REMOVE_GUEST), 0, UserHandle.SYSTEM) : null;
- Notification notification = new Notification.Builder(mContext)
+ Notification.Builder builder = new Notification.Builder(mContext)
.setVisibility(Notification.VISIBILITY_SECRET)
.setPriority(Notification.PRIORITY_MIN)
.setSmallIcon(R.drawable.ic_person)
@@ -557,10 +570,10 @@
.setShowWhen(false)
.addAction(R.drawable.ic_delete,
mContext.getString(R.string.guest_notification_remove_action),
- removeGuestPI)
- .build();
+ removeGuestPI);
+ SystemUI.overrideNotificationAppName(mContext, builder);
NotificationManager.from(mContext).notifyAsUser(TAG_REMOVE_GUEST, ID_REMOVE_GUEST,
- notification, new UserHandle(guestUserId));
+ builder.build(), new UserHandle(guestUserId));
}
private final Runnable mUnpauseRefreshUsers = new Runnable() {
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 ba191cd..3c9373b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -856,14 +856,6 @@
mNotificationParent.getNotificationColor());
}
- public void setRemoved() {
- int childCount = mChildren.size();
- for (int i = 0; i < childCount; i++) {
- ExpandableNotificationRow child = mChildren.get(i);
- child.setRemoved();
- }
- }
-
public int getPositionInLinearLayout(View childInGroup) {
int position = mNotificationHeaderMargin + mNotificatonTopPadding;
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 43f847c2..7de3879 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -1961,8 +1961,7 @@
// we're ending up at the same location as we are now, lets just skip the animation
bottom = finalBottom;
} else {
- bottom = (int) (lastView.getTranslationY() + lastView.getActualHeight()
- - lastView.getExtraBottomPadding());
+ bottom = (int) (lastView.getTranslationY() + lastView.getActualHeight());
bottom = Math.min(bottom, getHeight());
}
} else {
@@ -3690,6 +3689,9 @@
if (mAnimationsEnabled) {
mHeadsUpChangeAnimations.add(new Pair<>(row, isHeadsUp));
mNeedsAnimation = true;
+ if (!mIsExpanded && !isHeadsUp) {
+ row.setHeadsupDisappearRunning(true);
+ }
requestChildrenUpdate();
}
}
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 c8c7d3d..5eaea90 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -152,8 +152,10 @@
float newYTranslation = state.yTranslation;
float newHeight = state.height;
float newNotificationEnd = newYTranslation + newHeight;
-
- if (newYTranslation < previousNotificationEnd) {
+ boolean isHeadsUp = (child instanceof ExpandableNotificationRow)
+ && ((ExpandableNotificationRow) child).isPinned();
+ if (newYTranslation < previousNotificationEnd && ambientState.isShadeExpanded()
+ && !isHeadsUp) {
// The previous view is overlapping on top, clip!
float overlapAmount = previousNotificationEnd - newYTranslation;
state.clipTopAmount = (int) overlapAmount;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index 7ac0d80..659eaf7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -225,16 +225,22 @@
// start height animation
if (heightChanging) {
startHeightAnimation(child, viewState, duration, delay);
+ } else {
+ abortAnimation(child, TAG_ANIMATOR_HEIGHT);
}
// start shadow alpha animation
if (shadowAlphaChanging) {
startShadowAlphaAnimation(child, viewState, duration, delay);
+ } else {
+ abortAnimation(child, TAG_ANIMATOR_SHADOW_ALPHA);
}
// start top inset animation
if (topInsetChanging) {
startInsetAnimation(child, viewState, duration, delay);
+ } else {
+ abortAnimation(child, TAG_ANIMATOR_TOP_INSET);
}
// start dimmed animation
@@ -286,16 +292,29 @@
// start translationY animation
if (yTranslationChanging) {
startYTranslationAnimation(child, viewState, duration, delay);
+ } else {
+ abortAnimation(child, TAG_ANIMATOR_TRANSLATION_Y);
}
// start translationZ animation
if (zTranslationChanging) {
startZTranslationAnimation(child, viewState, duration, delay);
+ } else {
+ abortAnimation(child, TAG_ANIMATOR_TRANSLATION_Z);
}
// start alpha animation
if (alphaChanging && child.getTranslationX() == 0) {
startAlphaAnimation(child, viewState, duration, delay);
+ } else {
+ abortAnimation(child, TAG_ANIMATOR_ALPHA);
+ }
+ }
+
+ private void abortAnimation(View child, int animatorTag) {
+ Animator previousAnimator = getChildTag(child, animatorTag);
+ if (previousAnimator != null) {
+ previousAnimator.cancel();
}
}
@@ -413,7 +432,8 @@
animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
animator.setDuration(newDuration);
- if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
+ if (delay > 0 && (previousAnimator == null
+ || previousAnimator.getAnimatedFraction() == 0)) {
animator.setStartDelay(delay);
}
animator.addListener(getGlobalAnimationFinishedListener());
@@ -472,7 +492,8 @@
animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
animator.setDuration(newDuration);
- if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
+ if (delay > 0 && (previousAnimator == null
+ || previousAnimator.getAnimatedFraction() == 0)) {
animator.setStartDelay(delay);
}
animator.addListener(getGlobalAnimationFinishedListener());
@@ -548,7 +569,8 @@
animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
animator.setDuration(newDuration);
- if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
+ if (delay > 0 && (previousAnimator == null
+ || previousAnimator.getAnimatedFraction() == 0)) {
animator.setStartDelay(delay);
}
animator.addListener(getGlobalAnimationFinishedListener());
@@ -630,7 +652,8 @@
});
long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
animator.setDuration(newDuration);
- if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
+ if (delay > 0 && (previousAnimator == null
+ || previousAnimator.getAnimatedFraction() == 0)) {
animator.setStartDelay(delay);
}
animator.addListener(getGlobalAnimationFinishedListener());
@@ -674,7 +697,8 @@
animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
animator.setDuration(newDuration);
- if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
+ if (delay > 0 && (previousAnimator == null
+ || previousAnimator.getAnimatedFraction() == 0)) {
animator.setStartDelay(delay);
}
animator.addListener(getGlobalAnimationFinishedListener());
@@ -729,10 +753,12 @@
animator.setInterpolator(interpolator);
long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
animator.setDuration(newDuration);
- if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
+ if (delay > 0 && (previousAnimator == null
+ || previousAnimator.getAnimatedFraction() == 0)) {
animator.setStartDelay(delay);
}
animator.addListener(getGlobalAnimationFinishedListener());
+ final boolean isHeadsUpDisappear = mHeadsUpDisappearChildren.contains(child);
// remove the tag when the animation is finished
animator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -741,6 +767,9 @@
child.setTag(TAG_ANIMATOR_TRANSLATION_Y, null);
child.setTag(TAG_START_TRANSLATION_Y, null);
child.setTag(TAG_END_TRANSLATION_Y, null);
+ if (isHeadsUpDisappear) {
+ ((ExpandableNotificationRow) child).setHeadsupDisappearRunning(false);
+ }
}
});
startAnimator(animator);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 27726af..2d4900b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -257,4 +257,9 @@
} catch (RemoteException ex) {
}
}
+
+ @Override
+ public void handleSystemNavigationKey(int arg1) {
+ // Not implemented
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 36dd727..97d5e10 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -198,7 +198,7 @@
rec.getNickname());
final CharSequence text = mContext.getString(R.string.ext_media_missing_message);
- final Notification notif = new Notification.Builder(mContext)
+ Notification.Builder builder = new Notification.Builder(mContext)
.setSmallIcon(R.drawable.ic_sd_card_48dp)
.setColor(mContext.getColor(R.color.system_notification_accent_color))
.setContentTitle(title)
@@ -208,10 +208,11 @@
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setLocalOnly(true)
.setCategory(Notification.CATEGORY_SYSTEM)
- .setDeleteIntent(buildSnoozeIntent(fsUuid))
- .build();
+ .setDeleteIntent(buildSnoozeIntent(fsUuid));
+ SystemUI.overrideNotificationAppName(mContext, builder);
- mNotificationManager.notifyAsUser(fsUuid, PRIVATE_ID, notif, UserHandle.ALL);
+ mNotificationManager.notifyAsUser(fsUuid, PRIVATE_ID, builder
+ .build(), UserHandle.ALL);
}
}
}
@@ -224,7 +225,7 @@
final CharSequence text = mContext.getString(
R.string.ext_media_unsupported_notification_message, disk.getDescription());
- final Notification notif = new Notification.Builder(mContext)
+ Notification.Builder builder = new Notification.Builder(mContext)
.setSmallIcon(getSmallIcon(disk, VolumeInfo.STATE_UNMOUNTABLE))
.setColor(mContext.getColor(R.color.system_notification_accent_color))
.setContentTitle(title)
@@ -233,10 +234,11 @@
.setStyle(new Notification.BigTextStyle().bigText(text))
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setLocalOnly(true)
- .setCategory(Notification.CATEGORY_ERROR)
- .build();
+ .setCategory(Notification.CATEGORY_ERROR);
+ SystemUI.overrideNotificationAppName(mContext, builder);
- mNotificationManager.notifyAsUser(disk.getId(), DISK_ID, notif, UserHandle.ALL);
+ mNotificationManager.notifyAsUser(disk.getId(), DISK_ID, builder.build(),
+ UserHandle.ALL);
} else {
// Yay, we have volumes!
@@ -471,7 +473,7 @@
intent = buildWizardMigratePendingIntent(move);
}
- final Notification notif = new Notification.Builder(mContext)
+ Notification.Builder builder = new Notification.Builder(mContext)
.setSmallIcon(R.drawable.ic_sd_card_48dp)
.setColor(mContext.getColor(R.color.system_notification_accent_color))
.setContentTitle(title)
@@ -483,10 +485,11 @@
.setCategory(Notification.CATEGORY_PROGRESS)
.setPriority(Notification.PRIORITY_LOW)
.setProgress(100, status, false)
- .setOngoing(true)
- .build();
+ .setOngoing(true);
+ SystemUI.overrideNotificationAppName(mContext, builder);
- mNotificationManager.notifyAsUser(move.packageName, MOVE_ID, notif, UserHandle.ALL);
+ mNotificationManager.notifyAsUser(move.packageName, MOVE_ID,
+ builder.build(), UserHandle.ALL);
}
private void onMoveFinished(MoveInfo move, int status) {
@@ -520,7 +523,7 @@
intent = null;
}
- final Notification notif = new Notification.Builder(mContext)
+ Notification.Builder builder = new Notification.Builder(mContext)
.setSmallIcon(R.drawable.ic_sd_card_48dp)
.setColor(mContext.getColor(R.color.system_notification_accent_color))
.setContentTitle(title)
@@ -531,10 +534,11 @@
.setLocalOnly(true)
.setCategory(Notification.CATEGORY_SYSTEM)
.setPriority(Notification.PRIORITY_LOW)
- .setAutoCancel(true)
- .build();
+ .setAutoCancel(true);
+ SystemUI.overrideNotificationAppName(mContext, builder);
- mNotificationManager.notifyAsUser(move.packageName, MOVE_ID, notif, UserHandle.ALL);
+ mNotificationManager.notifyAsUser(move.packageName, MOVE_ID, builder.build(),
+ UserHandle.ALL);
}
private int getSmallIcon(DiskInfo disk, int state) {
@@ -555,7 +559,7 @@
private Notification.Builder buildNotificationBuilder(VolumeInfo vol, CharSequence title,
CharSequence text) {
- return new Notification.Builder(mContext)
+ Notification.Builder builder = new Notification.Builder(mContext)
.setSmallIcon(getSmallIcon(vol.getDisk(), vol.getState()))
.setColor(mContext.getColor(R.color.system_notification_accent_color))
.setContentTitle(title)
@@ -563,6 +567,8 @@
.setStyle(new Notification.BigTextStyle().bigText(text))
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setLocalOnly(true);
+ overrideNotificationAppName(mContext, builder);
+ return builder;
}
private PendingIntent buildInitPendingIntent(DiskInfo disk) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 1973e05..af6fec2 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -68,6 +68,7 @@
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
@@ -152,7 +153,7 @@
mKeyguard = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mAccessibilityMgr = (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
- mActiveSliderTint = loadColorStateList(R.color.system_accent_color);
+ mActiveSliderTint = ColorStateList.valueOf(Utils.getColorAccent(mContext));
mInactiveSliderTint = loadColorStateList(R.color.volume_slider_inactive);
initDialog();
@@ -562,6 +563,14 @@
if (!mExpanded && mExpandButtonAnimationRunning) {
prepareForCollapse();
}
+ final Resources res = mContext.getResources();
+ int paddingTop = mExpanded
+ ? res.getDimensionPixelSize(R.dimen.volume_dialog_expanded_padding_top)
+ : res.getDimensionPixelSize(R.dimen.volume_dialog_collapsed_padding_top);
+ mDialogContentView.setPaddingRelative(mDialogContentView.getPaddingStart(),
+ paddingTop,
+ mDialogContentView.getPaddingEnd(),
+ mDialogContentView.getPaddingBottom());
updateRowsH();
if (mExpandButtonAnimationRunning) {
final Drawable d = mExpandButton.getDrawable();
@@ -622,7 +631,6 @@
Util.setVisOrGone(row.view, visible);
Util.setVisOrGone(row.space, visible && mExpanded);
updateVolumeRowHeaderVisibleH(row);
- row.header.setAlpha(mExpanded && isActive ? 1 : 0.5f);
updateVolumeRowSliderTintH(row, isActive);
}
}
@@ -740,21 +748,7 @@
updateVolumeRowHeaderVisibleH(row);
// update header text
- String text = ss.name;
- if (mShowHeaders) {
- if (isRingZenNone) {
- text = mContext.getString(R.string.volume_stream_muted_dnd, ss.name);
- } else if (isRingVibrate && isRingLimited) {
- text = mContext.getString(R.string.volume_stream_vibrate_dnd, ss.name);
- } else if (isRingVibrate) {
- text = mContext.getString(R.string.volume_stream_vibrate, ss.name);
- } else if (ss.muted || mAutomute && ss.level == 0) {
- text = mContext.getString(R.string.volume_stream_muted, ss.name);
- } else if (isRingLimited) {
- text = mContext.getString(R.string.volume_stream_limited_dnd, ss.name);
- }
- }
- Util.setText(row.header, text);
+ Util.setText(row.header, ss.name);
// update icon
final boolean iconEnabled = (mAutomute || ss.muteSupported) && !zenMuted;
@@ -823,7 +817,7 @@
private void updateVolumeRowHeaderVisibleH(VolumeRow row) {
final boolean dynamic = row.ss != null && row.ss.dynamic;
- final boolean showHeaders = mShowHeaders || mExpanded && dynamic;
+ final boolean showHeaders = mExpanded && (mShowHeaders || dynamic);
if (row.cachedShowHeaders != showHeaders) {
row.cachedShowHeaders = showHeaders;
Util.setVisOrGone(row.header, showHeaders);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index 3d33809..44a435e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -122,7 +122,6 @@
private void applyConfiguration() {
mDialog.setStreamImportant(AudioManager.STREAM_ALARM, true);
mDialog.setStreamImportant(AudioManager.STREAM_SYSTEM, false);
- mDialog.setShowHeaders(false);
mDialog.setAutomute(true);
mDialog.setSilentMode(false);
mController.setVolumePolicy(mVolumePolicy);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java
index bbb70ed..04339eb 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java
@@ -43,7 +43,7 @@
public static final String PREF_ADJUST_ALARMS = "pref_adjust_alarms";
public static final String PREF_ADJUST_NOTIFICATION = "pref_adjust_notification";
- public static final boolean DEFAULT_SHOW_HEADERS = false;
+ public static final boolean DEFAULT_SHOW_HEADERS = true;
public static final boolean DEFAULT_ENABLE_AUTOMUTE = true;
public static final boolean DEFAULT_ENABLE_SILENT_MODE = true;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index 2688813..c820302 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -228,22 +228,23 @@
}
final Intent intent = new Intent(Receiver.DISABLE)
.putExtra(Receiver.EXTRA_COMPONENT, component);
+ Notification.Builder builder = new Notification.Builder(mContext)
+ .setSmallIcon(R.drawable.ic_volume_media)
+ .setWhen(0)
+ .setShowWhen(false)
+ .setOngoing(true)
+ .setContentTitle(mContext.getString(
+ R.string.volumeui_notification_title, getAppLabel(component)))
+ .setContentText(mContext.getString(R.string.volumeui_notification_text))
+ .setContentIntent(PendingIntent.getBroadcast(mContext, 0, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT))
+ .setPriority(Notification.PRIORITY_MIN)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color));
+ overrideNotificationAppName(mContext, builder);
mNotificationManager.notify(R.id.notification_volumeui,
- new Notification.Builder(mContext)
- .setSmallIcon(R.drawable.ic_volume_media)
- .setWhen(0)
- .setShowWhen(false)
- .setOngoing(true)
- .setContentTitle(mContext.getString(
- R.string.volumeui_notification_title, getAppLabel(component)))
- .setContentText(mContext.getString(R.string.volumeui_notification_text))
- .setContentIntent(PendingIntent.getBroadcast(mContext, 0, intent,
- PendingIntent.FLAG_UPDATE_CURRENT))
- .setPriority(Notification.PRIORITY_MIN)
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color))
- .build());
+ builder.build());
}
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
index a30f507..c93377a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
@@ -36,6 +36,8 @@
import android.util.ArraySet;
import android.util.Log;
+import org.mockito.Mockito;
+
@SmallTest
public class TileLifecycleManagerTests extends AndroidTestCase {
public static final String TILE_UPDATE_BROADCAST = "com.android.systemui.tests.TILE_UPDATE";
@@ -54,8 +56,11 @@
mThread = new HandlerThread("TestThread");
mThread.start();
mHandler = new Handler(mThread.getLooper());
+ ComponentName component = new ComponentName(mContext, FakeTileService.class);
mStateManager = new TileLifecycleManager(mHandler, getContext(),
- new Intent(mContext, FakeTileService.class), new UserHandle(UserHandle.myUserId()));
+ Mockito.mock(IQSService.class), new Tile(component),
+ new Intent().setComponent(component),
+ new UserHandle(UserHandle.myUserId()));
mCallbacks.clear();
getContext().registerReceiver(mReceiver, new IntentFilter(TILE_UPDATE_BROADCAST));
}
@@ -251,16 +256,6 @@
@Override
public IBinder onBind(Intent intent) {
return new IQSTileService.Stub() {
-
- @Override
- public void setQSService(IQSService service) {
-
- }
-
- @Override
- public void setQSTile(Tile tile) throws RemoteException {
- }
-
@Override
public void onTileAdded() throws RemoteException {
sendCallback("onTileAdded");
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
index 94c98d6..de3864d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
@@ -17,6 +17,7 @@
import android.content.ComponentName;
import android.os.Looper;
+import android.service.quicksettings.Tile;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.phone.QSTileHost;
@@ -109,7 +110,7 @@
}
@Override
- protected TileServiceManager onCreateTileService(ComponentName component) {
+ protected TileServiceManager onCreateTileService(ComponentName component, Tile qsTile) {
TileServiceManager manager = Mockito.mock(TileServiceManager.class);
mManagers.add(manager);
return manager;
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
index a3ea592..47d1493 100644
--- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -92,6 +92,11 @@
if (DEBUG) {
Slog.v(TAG, "Wallpaper is backup-eligible; linking & writing");
}
+
+ // In case of prior muddled state
+ infoStage.delete();
+ imageStage.delete();
+
Os.link(mWallpaperInfo.getCanonicalPath(), infoStage.getCanonicalPath());
fullBackupFile(infoStage, data);
Os.link(mWallpaperFile.getCanonicalPath(), imageStage.getCanonicalPath());
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 5527a41..a82d55f 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2323,6 +2323,41 @@
// Deletion helper encountered an error during photo and video deletion.
ACTION_DELETION_HELPER_PHOTOS_VIDEOS_DELETION_FAIL = 473;
+ // OPEN: Settings (root page if there are multiple tabs)
+ // CATEGORY: SETTINGS
+ DASHBOARD_CONTAINER = 474;
+
+ // OPEN: Settings -> SUPPORT TAB
+ // CATEGORY: SETTINGS
+ SUPPORT_FRAGMENT = 475;
+
+ // ACTION: Settings -> Select summary tab.
+ ACTION_SELECT_SUMMARY=476;
+
+ // ACTION: Settings -> Select support tab.
+ ACTION_SELECT_SUPPORT_FRAGMENT = 477;
+
+ // ACTION: Settings -> Support -> Tips & tricks
+ ACTION_SUPPORT_TIPS_AND_TRICKS = 478;
+
+ // ACTION: Settings -> Support -> Help & feedback
+ ACTION_SUPPORT_HELP_AND_FEEDBACK = 479;
+
+ // ACTION: Settings -> Support -> Sign in
+ ACTION_SUPPORT_SIGN_IN = 480;
+
+ // ACTION: Settings -> Support -> Phone
+ ACTION_SUPPORT_PHONE = 481;
+
+ // ACTION: Settings -> Support -> Chat
+ ACTION_SUPPORT_CHAT = 482;
+
+ // ACTION: Settings -> Support -> Phone/Chat -> Disclaimer Cancel
+ ACTION_SUPPORT_DISCLAIMER_CANCEL = 483;
+
+ // ACTION: Settings -> Support -> Phone/Chat -> Disclaimer OK
+ ACTION_SUPPORT_DISCLAIMER_OK = 484;
+
// ---- End N-MR1 Constants, all N-MR1 constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/services/Android.mk b/services/Android.mk
index 1918db5..3385bed 100644
--- a/services/Android.mk
+++ b/services/Android.mk
@@ -28,6 +28,7 @@
net \
print \
restrictions \
+ retaildemo \
usage \
usb \
voiceinteraction
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 7da969f..60d3339 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -2228,7 +2228,8 @@
@Override
public void handleMessage(Message message) {
final int eventType = message.what;
- notifyAccessibilityEventInternal(eventType);
+ AccessibilityEvent event = (AccessibilityEvent) message.obj;
+ notifyAccessibilityEventInternal(eventType, event);
}
};
@@ -3130,16 +3131,22 @@
// be modified to remove its source if the receiving service does
// not have permission to access the window content.
AccessibilityEvent newEvent = AccessibilityEvent.obtain(event);
- AccessibilityEvent oldEvent = mPendingEvents.get(eventType);
- mPendingEvents.put(eventType, newEvent);
-
- final int what = eventType;
- if (oldEvent != null) {
- mEventDispatchHandler.removeMessages(what);
- oldEvent.recycle();
+ Message message;
+ if ((mNotificationTimeout > 0)
+ && (eventType != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED)) {
+ // Allow at most one pending event
+ final AccessibilityEvent oldEvent = mPendingEvents.get(eventType);
+ mPendingEvents.put(eventType, newEvent);
+ if (oldEvent != null) {
+ mEventDispatchHandler.removeMessages(eventType);
+ oldEvent.recycle();
+ }
+ message = mEventDispatchHandler.obtainMessage(eventType);
+ } else {
+ // Send all messages, bypassing mPendingEvents
+ message = mEventDispatchHandler.obtainMessage(eventType, newEvent);
}
- Message message = mEventDispatchHandler.obtainMessage(what);
mEventDispatchHandler.sendMessageDelayed(message, mNotificationTimeout);
}
}
@@ -3149,9 +3156,8 @@
*
* @param eventType The type of the event to dispatch.
*/
- private void notifyAccessibilityEventInternal(int eventType) {
+ private void notifyAccessibilityEventInternal(int eventType, AccessibilityEvent event) {
IAccessibilityServiceClient listener;
- AccessibilityEvent event;
synchronized (mLock) {
listener = mServiceInterface;
@@ -3162,28 +3168,32 @@
return;
}
- event = mPendingEvents.get(eventType);
-
- // Check for null here because there is a concurrent scenario in which this
- // happens: 1) A binder thread calls notifyAccessibilityServiceDelayedLocked
- // which posts a message for dispatching an event. 2) The message is pulled
- // from the queue by the handler on the service thread and the latter is
- // just about to acquire the lock and call this method. 3) Now another binder
- // thread acquires the lock calling notifyAccessibilityServiceDelayedLocked
- // so the service thread waits for the lock; 4) The binder thread replaces
- // the event with a more recent one (assume the same event type) and posts a
- // dispatch request releasing the lock. 5) Now the main thread is unblocked and
- // dispatches the event which is removed from the pending ones. 6) And ... now
- // the service thread handles the last message posted by the last binder call
- // but the event is already dispatched and hence looking it up in the pending
- // ones yields null. This check is much simpler that keeping count for each
- // event type of each service to catch such a scenario since only one message
- // is processed at a time.
+ // There are two ways we notify for events, throttled and non-throttled. If we
+ // are not throttling, then messages come with events, which we handle with
+ // minimal fuss.
if (event == null) {
- return;
+ // We are throttling events, so we'll send the event for this type in
+ // mPendingEvents as long as it it's null. It can only null due to a race
+ // condition:
+ //
+ // 1) A binder thread calls notifyAccessibilityServiceDelayedLocked
+ // which posts a message for dispatching an event and stores the event
+ // in mPendingEvents.
+ // 2) The message is pulled from the queue by the handler on the service
+ // thread and this method is just about to acquire the lock.
+ // 3) Another binder thread acquires the lock in notifyAccessibilityEvent
+ // 4) notifyAccessibilityEvent recycles the event that this method was about
+ // to process, replaces it with a new one, and posts a second message
+ // 5) This method grabs the new event, processes it, and removes it from
+ // mPendingEvents
+ // 6) The second message dispatched in (4) arrives, but the event has been
+ // remvoved in (5).
+ event = mPendingEvents.get(eventType);
+ if (event == null) {
+ return;
+ }
+ mPendingEvents.remove(eventType);
}
-
- mPendingEvents.remove(eventType);
if (mSecurityPolicy.canRetrieveWindowContentLocked(this)) {
event.setConnectionId(mId);
} else {
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 04a0990..feceb14 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -20,6 +20,7 @@
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import android.annotation.UserIdInt;
import android.app.AlarmManager;
import android.app.AppGlobals;
import android.app.AppOpsManager;
@@ -67,6 +68,7 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.StorageManager;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.AtomicFile;
@@ -650,7 +652,7 @@
}
private void ensureGroupStateLoadedLocked(int userId, boolean enforceUserUnlockingOrUnlocked) {
- if (enforceUserUnlockingOrUnlocked && !mUserManager.isUserUnlockingOrUnlocked(userId)) {
+ if (enforceUserUnlockingOrUnlocked && !isUserRunningAndUnlocked(userId)) {
throw new IllegalStateException(
"User " + userId + " must be unlocked for widgets to be available");
}
@@ -695,6 +697,10 @@
loadGroupStateLocked(newProfileIds);
}
+ private boolean isUserRunningAndUnlocked(@UserIdInt int userId) {
+ return mUserManager.isUserRunning(userId) && StorageManager.isUserKeyUnlocked(userId);
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
@@ -3381,7 +3387,7 @@
if (userInfo != null && userInfo.isManagedProfile()) {
UserInfo parentInfo = mUserManager.getProfileParent(userId);
if (parentInfo != null
- && !mUserManager.isUserUnlockingOrUnlocked(parentInfo.getUserHandle())) {
+ && !isUserRunningAndUnlocked(parentInfo.getUserHandle().getIdentifier())) {
return true;
}
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 334b228..e6f99c1 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -725,6 +725,19 @@
return true;
}
+ /* adb backup: is this app only capable of doing key/value? We say otherwise if
+ * the app has a backup agent and does not say fullBackupOnly, *unless* it
+ * is a package that we know _a priori_ explicitly supports both key/value and
+ * full-data backup.
+ */
+ private static boolean appIsKeyValueOnly(PackageInfo pkg) {
+ if ("com.android.providers.settings".equals(pkg.packageName)) {
+ return false;
+ }
+
+ return !appGetsFullBackup(pkg);
+ }
+
// ----- Asynchronous backup/restore handler thread -----
private class BackupHandler extends Handler {
@@ -2356,7 +2369,8 @@
mConnecting = true;
mConnectedAgent = null;
try {
- if (mActivityManager.bindBackupAgent(app, mode)) {
+ if (mActivityManager.bindBackupAgent(app.packageName, mode,
+ UserHandle.USER_OWNER)) {
Slog.d(TAG, "awaiting agent for " + app);
// success; wait for the agent to arrive
@@ -3445,8 +3459,8 @@
Intent obbIntent = new Intent().setComponent(new ComponentName(
"com.android.sharedstoragebackup",
"com.android.sharedstoragebackup.ObbBackupService"));
- BackupManagerService.this.mContext.bindService(
- obbIntent, this, Context.BIND_AUTO_CREATE);
+ BackupManagerService.this.mContext.bindServiceAsUser(
+ obbIntent, this, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
}
public void tearDown() {
@@ -3964,7 +3978,7 @@
}
// Full backup task variant used for adb backup
- class PerformAdbBackupTask extends FullBackupTask {
+ class PerformAdbBackupTask extends FullBackupTask implements BackupRestoreTask {
FullBackupEngine mBackupEngine;
final AtomicBoolean mLatch;
@@ -3978,6 +3992,7 @@
boolean mIncludeSystem;
boolean mCompress;
ArrayList<String> mPackages;
+ PackageInfo mCurrentTarget;
String mCurrentPassword;
String mEncryptPassword;
@@ -4008,6 +4023,9 @@
} else {
mEncryptPassword = encryptPassword;
}
+ if (MORE_DEBUG) {
+ Slog.w(TAG, "Encrypting backup with passphrase=" + mEncryptPassword);
+ }
mCompress = doCompress;
}
@@ -4164,7 +4182,9 @@
Iterator<Entry<String, PackageInfo>> iter = packagesToBackup.entrySet().iterator();
while (iter.hasNext()) {
PackageInfo pkg = iter.next().getValue();
- if (!appIsEligibleForBackup(pkg.applicationInfo)) {
+ if (!appIsEligibleForBackup(pkg.applicationInfo)
+ || appIsStopped(pkg.applicationInfo)
+ || appIsKeyValueOnly(pkg)) {
iter.remove();
}
}
@@ -4266,9 +4286,11 @@
final boolean isSharedStorage =
pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
- mBackupEngine = new FullBackupEngine(out, null, pkg, mIncludeApks, null);
+ mBackupEngine = new FullBackupEngine(out, null, pkg, mIncludeApks, this);
sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName);
+
// Don't need to check preflight result as there is no preflight hook.
+ mCurrentTarget = pkg;
mBackupEngine.backupOnePackage();
// after the app's agent runs to handle its private filesystem
@@ -4307,6 +4329,28 @@
mWakelock.release();
}
}
+
+ // BackupRestoreTask methods, used for timeout handling
+ @Override
+ public void execute() {
+ // Unused
+ }
+
+ @Override
+ public void operationComplete(long result) {
+ // Unused
+ }
+
+ @Override
+ public void handleTimeout() {
+ final PackageInfo target = mCurrentTarget;
+ if (DEBUG) {
+ Slog.w(TAG, "adb backup timeout of " + target);
+ }
+ if (target != null) {
+ tearDownAgentAndKill(mCurrentTarget.applicationInfo);
+ }
+ }
}
// Full backup task extension used for transport-oriented operation
@@ -5254,7 +5298,7 @@
byte[] mWidgetData = null;
// Runner that can be placed in a separate thread to do in-process
- // invocations of the full restore API asynchronously
+ // invocations of the full restore API asynchronously. Used by adb restore.
class RestoreFileRunnable implements Runnable {
IBackupAgent mAgent;
FileMetadata mInfo;
@@ -6403,6 +6447,46 @@
// ***** end new engine class ***
+ // Used for synchronizing doRestoreFinished during adb restore
+ class AdbRestoreFinishedLatch implements BackupRestoreTask {
+ static final String TAG = "AdbRestoreFinishedLatch";
+ final CountDownLatch mLatch;
+
+ AdbRestoreFinishedLatch() {
+ mLatch = new CountDownLatch(1);
+ }
+
+ void await() {
+ boolean latched = false;
+ try {
+ latched = mLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ Slog.w(TAG, "Interrupted!");
+ }
+ }
+
+ @Override
+ public void execute() {
+ // Unused
+ }
+
+ @Override
+ public void operationComplete(long result) {
+ if (MORE_DEBUG) {
+ Slog.w(TAG, "adb onRestoreFinished() complete");
+ }
+ mLatch.countDown();
+ }
+
+ @Override
+ public void handleTimeout() {
+ if (DEBUG) {
+ Slog.w(TAG, "adb onRestoreFinished() timed out");
+ }
+ mLatch.countDown();
+ }
+ }
+
class PerformAdbRestoreTask implements Runnable {
ParcelFileDescriptor mInputFile;
String mCurrentPassword;
@@ -6418,6 +6502,27 @@
long mBytes;
+ // Runner that can be placed on a separate thread to do in-process invocation
+ // of the "restore finished" API asynchronously. Used by adb restore.
+ class RestoreFinishedRunnable implements Runnable {
+ final IBackupAgent mAgent;
+ final int mToken;
+
+ RestoreFinishedRunnable(IBackupAgent agent, int token) {
+ mAgent = agent;
+ mToken = token;
+ }
+
+ @Override
+ public void run() {
+ try {
+ mAgent.doRestoreFinished(mToken, mBackupManagerBinder);
+ } catch (RemoteException e) {
+ // never happens; this is used only for local binder calls
+ }
+ }
+ }
+
// possible handling states for a given package in the restore dataset
final HashMap<String, RestorePolicy> mPackagePolicies
= new HashMap<String, RestorePolicy>();
@@ -6559,7 +6664,7 @@
Slog.e(TAG, "Unable to read restore input");
} finally {
tearDownPipes();
- tearDownAgent(mTargetApp);
+ tearDownAgent(mTargetApp, true);
try {
if (rawDataIn != null) rawDataIn.close();
@@ -6713,7 +6818,7 @@
if (DEBUG) Slog.d(TAG, "Saw new package; finalizing old one");
// Now we're really done
tearDownPipes();
- tearDownAgent(mTargetApp);
+ tearDownAgent(mTargetApp, true);
mTargetApp = null;
mAgentPackage = null;
}
@@ -6935,10 +7040,12 @@
// okay, if the remote end failed at any point, deal with
// it by ignoring the rest of the restore on it
if (!agentSuccess) {
+ if (DEBUG) {
+ Slog.d(TAG, "Agent failure restoring " + pkg + "; now ignoring");
+ }
mBackupHandler.removeMessages(MSG_TIMEOUT);
tearDownPipes();
- tearDownAgent(mTargetApp);
- mAgent = null;
+ tearDownAgent(mTargetApp, false);
mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
}
}
@@ -6987,9 +7094,27 @@
}
}
- void tearDownAgent(ApplicationInfo app) {
+ void tearDownAgent(ApplicationInfo app, boolean doRestoreFinished) {
if (mAgent != null) {
try {
+ // In the adb restore case, we do restore-finished here
+ if (doRestoreFinished) {
+ final int token = generateToken();
+ final AdbRestoreFinishedLatch latch = new AdbRestoreFinishedLatch();
+ prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, latch);
+ if (mTargetApp.processName.equals("system")) {
+ if (MORE_DEBUG) {
+ Slog.d(TAG, "system agent - restoreFinished on thread");
+ }
+ Runnable runner = new RestoreFinishedRunnable(mAgent, token);
+ new Thread(runner, "restore-sys-finished-runner").start();
+ } else {
+ mAgent.doRestoreFinished(token, mBackupManagerBinder);
+ }
+
+ latch.await();
+ }
+
// unbind and tidy up even on timeout or failure, just in case
mActivityManager.unbindBackupAgent(app);
@@ -9353,7 +9478,7 @@
"com.android.backupconfirm.BackupRestoreConfirmation");
confIntent.putExtra(FullBackup.CONF_TOKEN_INTENT_EXTRA, token);
confIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(confIntent);
+ mContext.startActivityAsUser(confIntent, UserHandle.SYSTEM);
} catch (ActivityNotFoundException e) {
return false;
}
@@ -9597,6 +9722,15 @@
return list;
}
+ public String[] getTransportWhitelist() {
+ // No permission check, intentionally.
+ String[] whitelist = new String[mTransportWhitelist.size()];
+ for (int i = mTransportWhitelist.size() - 1; i >= 0; i--) {
+ whitelist[i] = mTransportWhitelist.valueAt(i).flattenToShortString();
+ }
+ return whitelist;
+ }
+
// Select which transport to use for the next backup operation.
public String selectBackupTransport(String transport) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index e745263..312b878 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -275,6 +275,12 @@
}
@Override
+ public String[] getTransportWhitelist() {
+ BackupManagerService svc = mService;
+ return (svc != null) ? svc.getTransportWhitelist() : null;
+ }
+
+ @Override
public String selectBackupTransport(String transport) throws RemoteException {
BackupManagerService svc = mService;
return (svc != null) ? svc.selectBackupTransport(transport) : null;
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 400c4a7..312553a 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -3074,9 +3074,6 @@
if (alarm.workSource != null && alarm.workSource.size() > 0) {
for (int wi=0; wi<alarm.workSource.size(); wi++) {
final String wsName = alarm.workSource.getName(wi);
- if (wsName == null) {
- Slog.w(TAG, "Null worksource name for alarm " + alarm);
- }
ActivityManagerNative.noteWakeupAlarm(
alarm.operation, alarm.workSource.get(wi),
(wsName != null) ? wsName : alarm.packageName,
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 71964d1..baa0bbe 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -1171,8 +1171,27 @@
}
mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
mEnable = true;
+
+ // Use service interface to get the exact state
+ try {
+ mBluetoothLock.readLock().lock();
+ if (mBluetooth != null) {
+ int state = mBluetooth.getState();
+ if (state == BluetoothAdapter.STATE_BLE_ON) {
+ Slog.w(TAG, "BT is in BLE_ON State");
+ mBluetooth.onLeServiceUp();
+ break;
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "", e);
+ } finally {
+ mBluetoothLock.readLock().unlock();
+ }
+
+ mQuietEnable = (msg.arg1 == 1);
if (mBluetooth == null) {
- handleEnable(msg.arg1 == 1);
+ handleEnable(mQuietEnable);
} else {
//
// We need to wait until transitioned to STATE_OFF and
@@ -1190,7 +1209,6 @@
// on the order of (2 * SERVICE_RESTART_TIME_MS).
//
waitForOnOff(false, true);
- mQuietEnable = (msg.arg1 == 1);
Message restartMsg = mHandler.obtainMessage(
MESSAGE_RESTART_BLUETOOTH_SERVICE);
mHandler.sendMessageDelayed(restartMsg,
@@ -1353,17 +1371,30 @@
// handle error state transition case from TURNING_ON to OFF
// unbind and rebind bluetooth service and enable bluetooth
if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_ON) &&
- (newState == BluetoothAdapter.STATE_OFF) &&
- (mBluetooth != null) && mEnable) {
+ (newState == BluetoothAdapter.STATE_OFF) &&
+ (mBluetooth != null) && mEnable) {
recoverBluetoothServiceFromError();
}
if ((prevState == BluetoothAdapter.STATE_TURNING_ON) &&
- (newState == BluetoothAdapter.STATE_BLE_ON) &&
- (mBluetooth != null) && mEnable) {
+ (newState == BluetoothAdapter.STATE_BLE_ON) &&
+ (mBluetooth != null) && mEnable) {
recoverBluetoothServiceFromError();
}
+ // If we tried to enable BT while BT was in the process of shutting down,
+ // wait for the BT process to fully tear down and then force a restart
+ // here. This is a bit of a hack (b/29363429).
+ if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_OFF) &&
+ (newState == BluetoothAdapter.STATE_OFF)) {
+ if (mEnable) {
+ Slog.d(TAG, "Entering STATE_OFF but mEnabled is true; restarting.");
+ waitForOnOff(false, true);
+ Message restartMsg = mHandler.obtainMessage(
+ MESSAGE_RESTART_BLUETOOTH_SERVICE);
+ mHandler.sendMessageDelayed(restartMsg, 2 * SERVICE_RESTART_TIME_MS);
+ }
+ }
if (newState == BluetoothAdapter.STATE_ON ||
- newState == BluetoothAdapter.STATE_BLE_ON) {
+ newState == BluetoothAdapter.STATE_BLE_ON) {
// bluetooth is working, reset the counter
if (mErrorRecoveryRetryCounter != 0) {
Slog.w(TAG, "bluetooth is recovered from error");
@@ -1406,7 +1437,7 @@
// Send BT state broadcast to update
// the BT icon correctly
if ((mState == BluetoothAdapter.STATE_TURNING_ON) ||
- (mState == BluetoothAdapter.STATE_ON)) {
+ (mState == BluetoothAdapter.STATE_ON)) {
bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
BluetoothAdapter.STATE_TURNING_OFF);
mState = BluetoothAdapter.STATE_TURNING_OFF;
@@ -1639,8 +1670,8 @@
boolean isStandardBroadcast = true;
if (prevState != newState) {
//Notify all proxy objects first of adapter state change
- if (newState == BluetoothAdapter.STATE_BLE_ON
- || newState == BluetoothAdapter.STATE_OFF) {
+ if (newState == BluetoothAdapter.STATE_BLE_ON ||
+ newState == BluetoothAdapter.STATE_OFF) {
boolean intermediate_off = (prevState == BluetoothAdapter.STATE_TURNING_OFF
&& newState == BluetoothAdapter.STATE_BLE_ON);
@@ -1685,13 +1716,13 @@
sendBluetoothStateCallback(isUp);
sendBleStateChanged(prevState, newState);
- } else if (newState == BluetoothAdapter.STATE_BLE_TURNING_ON
- || newState == BluetoothAdapter.STATE_BLE_TURNING_OFF ) {
+ } else if (newState == BluetoothAdapter.STATE_BLE_TURNING_ON ||
+ newState == BluetoothAdapter.STATE_BLE_TURNING_OFF ) {
sendBleStateChanged(prevState, newState);
isStandardBroadcast = false;
- } else if (newState == BluetoothAdapter.STATE_TURNING_ON
- || newState == BluetoothAdapter.STATE_TURNING_OFF) {
+ } else if (newState == BluetoothAdapter.STATE_TURNING_ON ||
+ newState == BluetoothAdapter.STATE_TURNING_OFF) {
sendBleStateChanged(prevState, newState);
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index e65b50c..a338f6f 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -30,8 +30,6 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
-import static android.net.NetworkPolicyManager.MASK_METERED_NETWORKS;
-import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS;
import static android.net.NetworkPolicyManager.RULE_NONE;
import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
@@ -932,7 +930,7 @@
// Networks aren't blocked when ignoring blocked status
if (ignoreBlocked) return false;
// Networks are never blocked for system services
- if (uid < Process.FIRST_APPLICATION_UID) return false;
+ if (isSystem(uid)) return false;
final boolean networkMetered;
final int uidRules;
@@ -4046,12 +4044,18 @@
return false;
}
+ private boolean isSystem(int uid) {
+ return uid < Process.FIRST_APPLICATION_UID;
+ }
private void enforceMeteredApnPolicy(NetworkCapabilities networkCapabilities) {
+ final int uid = Binder.getCallingUid();
+ if (isSystem(uid)) {
+ return;
+ }
// if UID is restricted, don't allow them to bring up metered APNs
if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED) == false) {
final int uidRules;
- final int uid = Binder.getCallingUid();
synchronized(mRulesLock) {
uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
}
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index bb966f7..afed5ef 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -212,7 +212,6 @@
private int mActiveIdleOpCount;
private PowerManager.WakeLock mActiveIdleWakeLock;
- private IBinder mDownloadServiceActive;
private boolean mJobsActive;
private boolean mAlarmsActive;
private boolean mReportedMaintenanceActivity;
@@ -607,7 +606,7 @@
* This is the minimum amount of time that we will stay in maintenance mode after
* a light doze. We have this minimum to allow various things to respond to switching
* in to maintenance mode and scheduling their work -- otherwise we may
- * see there is nothing to do (no jobs or downloads pending) and go out of maintenance
+ * see there is nothing to do (no jobs pending) and go out of maintenance
* mode immediately.
* @see Settings.Global#DEVICE_IDLE_CONSTANTS
* @see #KEY_MIN_LIGHT_MAINTENANCE_TIME
@@ -618,7 +617,7 @@
* This is the minimum amount of time that we will stay in maintenance mode after
* a full doze. We have this minimum to allow various things to respond to switching
* in to maintenance mode and scheduling their work -- otherwise we may
- * see there is nothing to do (no jobs or downloads pending) and go out of maintenance
+ * see there is nothing to do (no jobs pending) and go out of maintenance
* mode immediately.
* @see Settings.Global#DEVICE_IDLE_CONSTANTS
* @see #KEY_MIN_DEEP_MAINTENANCE_TIME
@@ -1220,28 +1219,6 @@
}
}
- @Override public void downloadServiceActive(IBinder token) {
- getContext().enforceCallingOrSelfPermission(
- "android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS", null);
- long ident = Binder.clearCallingIdentity();
- try {
- DeviceIdleController.this.downloadServiceActive(token);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override public void downloadServiceInactive() {
- getContext().enforceCallingOrSelfPermission(
- "android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS", null);
- long ident = Binder.clearCallingIdentity();
- try {
- DeviceIdleController.this.downloadServiceInactive();
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
@Override public boolean registerMaintenanceActivityListener(
IMaintenanceActivityListener listener) {
return DeviceIdleController.this.registerMaintenanceActivityListener(listener);
@@ -2086,30 +2063,6 @@
}
}
- void downloadServiceActive(IBinder token) {
- synchronized (this) {
- mDownloadServiceActive = token;
- reportMaintenanceActivityIfNeededLocked();
- try {
- token.linkToDeath(new IBinder.DeathRecipient() {
- @Override public void binderDied() {
- downloadServiceInactive();
- }
- }, 0);
- } catch (RemoteException e) {
- mDownloadServiceActive = null;
- }
- }
- }
-
- void downloadServiceInactive() {
- synchronized (this) {
- mDownloadServiceActive = null;
- reportMaintenanceActivityIfNeededLocked();
- exitMaintenanceEarlyIfNeededLocked();
- }
- }
-
void setJobsActive(boolean active) {
synchronized (this) {
mJobsActive = active;
@@ -2143,7 +2096,7 @@
}
void reportMaintenanceActivityIfNeededLocked() {
- boolean active = mJobsActive | (mDownloadServiceActive != null);
+ boolean active = mJobsActive;
if (active == mReportedMaintenanceActivity) {
return;
}
@@ -2154,8 +2107,7 @@
}
boolean isOpsInactiveLocked() {
- return mActiveIdleOpCount <= 0 && mDownloadServiceActive == null
- && !mJobsActive && !mAlarmsActive;
+ return mActiveIdleOpCount <= 0 && !mJobsActive && !mAlarmsActive;
}
void exitMaintenanceEarlyIfNeededLocked() {
@@ -3053,9 +3005,6 @@
if (mAlarmsActive) {
pw.print(" mAlarmsActive="); pw.println(mAlarmsActive);
}
- if (mDownloadServiceActive != null) {
- pw.print(" mDownloadServiceActive="); pw.println(mDownloadServiceActive);
- }
}
}
diff --git a/services/core/java/com/android/server/InputContentUriTokenHandler.java b/services/core/java/com/android/server/InputContentUriTokenHandler.java
new file mode 100644
index 0000000..3f4972b
--- /dev/null
+++ b/services/core/java/com/android/server/InputContentUriTokenHandler.java
@@ -0,0 +1,121 @@
+/*
+** 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.
+*/
+
+package com.android.server;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.app.ActivityManagerNative;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.inputmethod.IInputContentUriToken;
+
+final class InputContentUriTokenHandler extends IInputContentUriToken.Stub {
+
+ @NonNull
+ private final Uri mUri;
+ private final int mSourceUid;
+ @NonNull
+ private final String mTargetPackage;
+ @UserIdInt
+ private final int mSourceUserId;
+ @UserIdInt
+ private final int mTargetUserId;
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private IBinder mPermissionOwnerToken = null;
+
+ InputContentUriTokenHandler(@NonNull Uri contentUri, int sourceUid,
+ @NonNull String targetPackage, @UserIdInt int sourceUserId,
+ @UserIdInt int targetUserId) {
+ mUri = contentUri;
+ mSourceUid = sourceUid;
+ mTargetPackage = targetPackage;
+ mSourceUserId = sourceUserId;
+ mTargetUserId = targetUserId;
+ }
+
+ @Override
+ public void take() {
+ synchronized (mLock) {
+ if (mPermissionOwnerToken != null) {
+ // Permission is already granted.
+ return;
+ }
+
+ try {
+ mPermissionOwnerToken = ActivityManagerNative.getDefault()
+ .newUriPermissionOwner("InputContentUriTokenHandler");
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+
+ doTakeLocked(mPermissionOwnerToken);
+ }
+ }
+
+ private void doTakeLocked(@NonNull IBinder permissionOwner) {
+ long origId = Binder.clearCallingIdentity();
+ try {
+ try {
+ ActivityManagerNative.getDefault().grantUriPermissionFromOwner(
+ permissionOwner, mSourceUid, mTargetPackage, mUri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION, mSourceUserId, mTargetUserId);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
+ public void release() {
+ synchronized (mLock) {
+ if (mPermissionOwnerToken == null) {
+ return;
+ }
+ try {
+ ActivityManagerNative.getDefault().revokeUriPermissionFromOwner(
+ mPermissionOwnerToken, mUri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION, mSourceUserId);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ } finally {
+ mPermissionOwnerToken = null;
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ release();
+ } finally {
+ super.finalize();
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 5d8fe7c..e0d89f2 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -18,6 +18,7 @@
import static java.lang.annotation.RetentionPolicy.SOURCE;
import com.android.internal.content.PackageMonitor;
+import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController;
import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
import com.android.internal.inputmethod.InputMethodUtils;
@@ -137,6 +138,7 @@
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.nio.charset.StandardCharsets;
+import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -3911,6 +3913,52 @@
}
@Override
+ public IInputContentUriToken createInputContentUriToken(@Nullable IBinder token,
+ @Nullable Uri contentUri, @Nullable String packageName) {
+ if (!calledFromValidUser()) {
+ return null;
+ }
+
+ if (token == null) {
+ throw new NullPointerException("token");
+ }
+ if (packageName == null) {
+ throw new NullPointerException("packageName");
+ }
+ if (contentUri == null) {
+ throw new NullPointerException("contentUri");
+ }
+ final String contentUriScheme = contentUri.getScheme();
+ if (!"content".equals(contentUriScheme)) {
+ throw new InvalidParameterException("contentUri must have content scheme");
+ }
+
+ synchronized (mMethodMap) {
+ final int uid = Binder.getCallingUid();
+ if (mCurMethodId == null) {
+ return null;
+ }
+ if (mCurToken != token) {
+ Slog.e(TAG, "Ignoring createInputContentUriToken mCurToken=" + mCurToken
+ + " token=" + token);
+ return null;
+ }
+ // We cannot simply distinguish a bad IME that reports an arbitrary package name from
+ // an unfortunate IME whose internal state is already obsolete due to the asynchronous
+ // nature of our system. Let's compare it with our internal record.
+ if (!TextUtils.equals(mCurAttribute.packageName, packageName)) {
+ Slog.e(TAG, "Ignoring createInputContentUriToken mCurAttribute.packageName="
+ + mCurAttribute.packageName + " packageName=" + packageName);
+ return null;
+ }
+ final int imeUserId = UserHandle.getUserId(uid);
+ final int appUserId = UserHandle.getUserId(mCurClient.uid);
+ return new InputContentUriTokenHandler(contentUri, uid, packageName, imeUserId,
+ appUserId);
+ }
+ }
+
+ @Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index ef7b787..d64fe32 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -423,6 +423,9 @@
if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
// Notify keystore that a new user was added.
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
+ if (userHandle > UserHandle.USER_SYSTEM) {
+ removeUser(userHandle, /* unknownUser= */ true);
+ }
final KeyStore ks = KeyStore.getInstance();
final UserInfo parentInfo = mUserManager.getProfileParent(userHandle);
final int parentHandle = parentInfo != null ? parentInfo.id : -1;
@@ -433,7 +436,7 @@
} else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
if (userHandle > 0) {
- removeUser(userHandle);
+ removeUser(userHandle, /* unknownUser= */ false);
}
}
}
@@ -1465,7 +1468,7 @@
return false;
}
- private void removeUser(int userId) {
+ private void removeUser(int userId, boolean unknownUser) {
mStorage.removeUser(userId);
mStrongAuth.removeUser(userId);
@@ -1480,7 +1483,7 @@
} catch (RemoteException ex) {
Slog.w(TAG, "unable to clear GK secure user id");
}
- if (mUserManager.getUserInfo(userId).isManagedProfile()) {
+ if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) {
removeKeystoreProfileKey(userId);
}
}
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 9c75a00..cdd977b 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -827,8 +827,9 @@
if (provider != null) {
final IActivityManager am = ActivityManagerNative.getDefault();
try {
- am.killApplicationWithAppId(provider.applicationInfo.packageName,
- UserHandle.getAppId(provider.applicationInfo.uid), "vold reset");
+ am.killApplication(provider.applicationInfo.packageName,
+ UserHandle.getAppId(provider.applicationInfo.uid),
+ UserHandle.USER_ALL, "vold reset");
// We only need to run this once. It will kill all users' media processes.
break;
} catch (RemoteException e) {
@@ -2030,6 +2031,9 @@
enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
waitForReady();
+ final VolumeInfo from;
+ final VolumeInfo to;
+
synchronized (mLock) {
if (Objects.equals(mPrimaryStorageUuid, volumeUuid)) {
throw new IllegalArgumentException("Primary storage already at " + volumeUuid);
@@ -2049,10 +2053,11 @@
onMoveStatusLocked(MOVE_STATUS_COPY_FINISHED);
onMoveStatusLocked(PackageManager.MOVE_SUCCEEDED);
mHandler.obtainMessage(H_RESET).sendToTarget();
+ return;
} else {
- final VolumeInfo from = findStorageForUuid(mPrimaryStorageUuid);
- final VolumeInfo to = findStorageForUuid(volumeUuid);
+ from = findStorageForUuid(mPrimaryStorageUuid);
+ to = findStorageForUuid(volumeUuid);
if (from == null) {
Slog.w(TAG, "Failing move due to missing from volume " + mPrimaryStorageUuid);
@@ -2063,14 +2068,14 @@
onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
return;
}
-
- try {
- mConnector.execute("volume", "move_storage", from.id, to.id);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
- }
}
}
+
+ try {
+ mConnector.execute("volume", "move_storage", from.id, to.id);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
}
@Override
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 7f3eb15..ab036c7 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -487,7 +487,7 @@
private boolean shouldVibrateForRingtone() {
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
- int ringerMode = audioManager.getRingerMode();
+ int ringerMode = audioManager.getRingerModeInternal();
// "Also vibrate for calls" Setting in Sound
if (Settings.System.getInt(
mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 0cf5172..f7bd04b 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -3538,7 +3538,7 @@
@Override
public void addSharedAccountsFromParentUser(int parentUserId, int userId) {
- checkManageUsersPermission("addSharedAccountsFromParentUser");
+ checkManageOrCreateUsersPermission("addSharedAccountsFromParentUser");
Account[] accounts = getAccountsAsUser(null, parentUserId, mContext.getOpPackageName());
for (Account account : accounts) {
addSharedAccountAsUser(account, userId);
@@ -5092,6 +5092,16 @@
}
}
+ private static void checkManageOrCreateUsersPermission(String message) {
+ if (ActivityManager.checkComponentPermission(android.Manifest.permission.MANAGE_USERS,
+ Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED &&
+ ActivityManager.checkComponentPermission(android.Manifest.permission.CREATE_USERS,
+ Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("You need MANAGE_USERS or CREATE_USERS permission to: "
+ + message);
+ }
+ }
+
private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
int callerUid) {
if (callerUid == Process.SYSTEM_UID) {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index dcd9b0c..7986629 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1443,6 +1443,12 @@
boolean allowCancel) {
boolean canceled = false;
+ if (mAm.isShuttingDownLocked()) {
+ Slog.w(TAG, "Not scheduling restart of crashed service " + r.shortName
+ + " - system is shutting down");
+ return false;
+ }
+
ServiceMap smap = getServiceMap(r.userId);
if (smap.mServicesByName.get(r.name) != r) {
ServiceRecord cur = smap.mServicesByName.get(r.name);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2c7ef7e..b5b115c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -63,6 +63,7 @@
import org.xmlpull.v1.XmlSerializer;
import android.Manifest;
+import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityManager;
@@ -102,7 +103,6 @@
import android.app.PendingIntent;
import android.app.ProfilerInfo;
import android.app.admin.DevicePolicyManager;
-import android.app.admin.DevicePolicyManagerInternal;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.app.backup.IBackupManager;
@@ -205,6 +205,7 @@
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.DebugUtils;
+import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
import android.util.Pair;
@@ -273,6 +274,10 @@
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.res.Configuration.UI_MODE_TYPE_TELEVISION;
+import static android.os.Process.PROC_CHAR;
+import static android.os.Process.PROC_OUT_LONG;
+import static android.os.Process.PROC_PARENS;
+import static android.os.Process.PROC_SPACE_TERM;
import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
import static android.provider.Settings.Global.DEBUG_APP;
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
@@ -500,7 +505,10 @@
static final String[] EMPTY_STRING_ARRAY = new String[0];
// How many bytes to write into the dropbox log before truncating
- static final int DROPBOX_MAX_SIZE = 256 * 1024;
+ static final int DROPBOX_MAX_SIZE = 192 * 1024;
+ // Assumes logcat entries average around 100 bytes; that's not perfect stack traces count
+ // as one line, but close enough for now.
+ static final int RESERVED_BYTES_PER_LOGCAT_LINE = 100;
// Access modes for handleIncomingUser.
static final int ALLOW_NON_FULL = 0;
@@ -1513,6 +1521,7 @@
static final int NOTIFY_FORCED_RESIZABLE_MSG = 67;
static final int NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG = 68;
static final int VR_MODE_APPLY_IF_NEEDED_MSG = 69;
+ static final int SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG = 70;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1523,6 +1532,7 @@
static KillHandler sKillHandler = null;
CompatModeDialog mCompatModeDialog;
+ UnsupportedDisplaySizeDialog mUnsupportedDisplaySizeDialog;
long mLastMemUsageReportTime = 0;
/**
@@ -1693,6 +1703,22 @@
}
break;
}
+ case SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG: {
+ synchronized (ActivityManagerService.this) {
+ final ActivityRecord ar = (ActivityRecord) msg.obj;
+ if (mUnsupportedDisplaySizeDialog != null) {
+ mUnsupportedDisplaySizeDialog.dismiss();
+ mUnsupportedDisplaySizeDialog = null;
+ }
+ if (ar != null && mCompatModePackages.getPackageNotifyUnsupportedZoomLocked(
+ ar.packageName)) {
+ mUnsupportedDisplaySizeDialog = new UnsupportedDisplaySizeDialog(
+ ActivityManagerService.this, mContext, ar.info.applicationInfo);
+ mUnsupportedDisplaySizeDialog.show();
+ }
+ }
+ break;
+ }
case START_USER_SWITCH_UI_MSG: {
mUserController.showUserSwitchDialog((Pair<UserInfo, UserInfo>) msg.obj);
break;
@@ -1827,13 +1853,13 @@
} break;
case KILL_APPLICATION_MSG: {
synchronized (ActivityManagerService.this) {
- int appid = msg.arg1;
- boolean restart = (msg.arg2 == 1);
+ final int appId = msg.arg1;
+ final int userId = msg.arg2;
Bundle bundle = (Bundle)msg.obj;
String pkg = bundle.getString("pkg");
String reason = bundle.getString("reason");
- forceStopPackageLocked(pkg, appid, restart, false, true, false,
- false, UserHandle.USER_ALL, reason);
+ forceStopPackageLocked(pkg, appId, false, false, true, false,
+ false, userId, reason);
}
} break;
case FINALIZE_PENDING_INTENT_MSG: {
@@ -3099,6 +3125,16 @@
mUiHandler.sendMessage(msg);
}
+ final void showUnsupportedZoomDialogIfNeededLocked(ActivityRecord r) {
+ if (mConfiguration.densityDpi != DisplayMetrics.DENSITY_DEVICE_STABLE
+ && r.appInfo.requiresSmallestWidthDp > mConfiguration.smallestScreenWidthDp) {
+ final Message msg = Message.obtain();
+ msg.what = SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG;
+ msg.obj = r;
+ mUiHandler.sendMessage(msg);
+ }
+ }
+
private int updateLruProcessInternalLocked(ProcessRecord app, long now, int index,
String what, Object obj, ProcessRecord srcApp) {
app.lastActivityTime = now;
@@ -3492,13 +3528,11 @@
// app launch boost for big.little configurations
// use cpusets to migrate freshly launched tasks to big cores
- synchronized(ActivityManagerService.this) {
- nativeMigrateToBoost();
- mIsBoosted = true;
- mBoostStartTime = SystemClock.uptimeMillis();
- Message msg = mHandler.obtainMessage(APP_BOOST_DEACTIVATE_MSG);
- mHandler.sendMessageDelayed(msg, APP_BOOST_MESSAGE_DELAY);
- }
+ nativeMigrateToBoost();
+ mIsBoosted = true;
+ mBoostStartTime = SystemClock.uptimeMillis();
+ Message msg = mHandler.obtainMessage(APP_BOOST_DEACTIVATE_MSG);
+ mHandler.sendMessageDelayed(msg, APP_BOOST_MESSAGE_DELAY);
// We don't have to do anything more if:
// (1) There is an existing application record; and
@@ -3511,7 +3545,7 @@
+ " thread=" + (app != null ? app.thread : null)
+ " pid=" + (app != null ? app.pid : -1));
if (app != null && app.pid > 0) {
- if (!knownToBeDead || app.thread == null) {
+ if ((!knownToBeDead && !app.killed) || app.thread == null) {
// We already have the app running, or are waiting for it to
// come up (we have a pid but not yet its thread), so keep it.
if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App already running: " + app);
@@ -5687,12 +5721,12 @@
* The pkg name and app id have to be specified.
*/
@Override
- public void killApplicationWithAppId(String pkg, int appid, String reason) {
+ public void killApplication(String pkg, int appId, int userId, String reason) {
if (pkg == null) {
return;
}
// Make sure the uid is valid.
- if (appid < 0) {
+ if (appId < 0) {
Slog.w(TAG, "Invalid appid specified for pkg : " + pkg);
return;
}
@@ -5701,8 +5735,8 @@
if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
// Post an aysnc message to kill the application
Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
- msg.arg1 = appid;
- msg.arg2 = 0;
+ msg.arg1 = appId;
+ msg.arg2 = userId;
Bundle bundle = new Bundle();
bundle.putString("pkg", pkg);
bundle.putString("reason", reason);
@@ -6386,7 +6420,7 @@
EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);
app.makeActive(thread, mProcessStats);
- app.curAdj = app.setAdj = ProcessList.INVALID_ADJ;
+ app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
app.curSchedGroup = app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.forcingToForeground = null;
updateProcessForegroundLocked(app, false, false);
@@ -8307,7 +8341,7 @@
final IPackageManager pm = AppGlobals.getPackageManager();
final String authority = grantUri.uri.getAuthority();
final ProviderInfo pi = getProviderInfoLocked(authority, grantUri.sourceUserId,
- MATCH_DEBUG_TRIAGED_MISSING);
+ MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
if (pi == null) {
Slog.w(TAG, "No content provider found for permission revoke: "
+ grantUri.toSafeString());
@@ -8405,7 +8439,7 @@
final String authority = uri.getAuthority();
final ProviderInfo pi = getProviderInfoLocked(authority, userId,
- MATCH_DEBUG_TRIAGED_MISSING);
+ MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
if (pi == null) {
Slog.w(TAG, "No content provider found for permission revoke: "
+ uri.toSafeString());
@@ -8802,10 +8836,11 @@
Preconditions.checkNotNull(packageName, "packageName");
final int callingUid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(callingUid);
final IPackageManager pm = AppGlobals.getPackageManager();
try {
- final int packageUid = pm.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING,
- UserHandle.getUserId(callingUid));
+ final int packageUid = pm.getPackageUid(packageName,
+ MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, callingUserId);
if (packageUid != callingUid) {
throw new SecurityException(
"Package " + packageName + " does not belong to calling UID " + callingUid);
@@ -8822,30 +8857,8 @@
if (perms == null) {
Slog.w(TAG, "No permission grants found for " + packageName);
} else {
- final int userId = UserHandle.getUserId(callingUid);
- Set<String> existingAuthorities = null;
-
for (UriPermission perm : perms.values()) {
if (packageName.equals(perm.targetPkg) && perm.persistedModeFlags != 0) {
- // Is this provider available in the current boot state? If the user
- // is not running and unlocked we check if the provider package exists.
- if (!mUserController.isUserRunningLocked(userId,
- ActivityManager.FLAG_AND_UNLOCKED)) {
- String authority = perm.uri.uri.getAuthority();
- if (existingAuthorities == null
- || !existingAuthorities.contains(authority)) {
- ProviderInfo providerInfo = getProviderInfoLocked(authority,
- userId, MATCH_DEBUG_TRIAGED_MISSING);
- if (providerInfo != null) {
- if (existingAuthorities == null) {
- existingAuthorities = new ArraySet<>();
- }
- existingAuthorities.add(authority);
- } else {
- continue;
- }
- }
- }
result.add(perm.buildPersistedPublicApiObject());
}
}
@@ -9234,9 +9247,6 @@
// sense, so turn off auto-remove.
intent.addFlags(Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS);
}
- } else if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
- // Must be a new task.
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
if (!comp.equals(mLastAddedTaskComponent) || callingUid != mLastAddedTaskUid) {
mLastAddedTaskActivity = null;
@@ -10509,6 +10519,30 @@
}
}
+ private static final int[] PROCESS_STATE_STATS_FORMAT = new int[] {
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM|PROC_PARENS,
+ PROC_SPACE_TERM|PROC_CHAR|PROC_OUT_LONG, // 3: process state
+ };
+
+ private final long[] mProcessStateStatsLongs = new long[1];
+
+ boolean isProcessAliveLocked(ProcessRecord proc) {
+ if (proc.procStatFile == null) {
+ proc.procStatFile = "/proc/" + proc.pid + "/stat";
+ }
+ mProcessStateStatsLongs[0] = 0;
+ if (!Process.readProcFile(proc.procStatFile, PROCESS_STATE_STATS_FORMAT, null,
+ mProcessStateStatsLongs, null)) {
+ if (DEBUG_OOM_ADJ) Slog.d(TAG, "UNABLE TO RETRIEVE STATE FOR " + proc.procStatFile);
+ return false;
+ }
+ final long state = mProcessStateStatsLongs[0];
+ if (DEBUG_OOM_ADJ) Slog.d(TAG, "RETRIEVED STATE FOR " + proc.procStatFile + ": "
+ + (char)state);
+ return state != 'Z' && state != 'X' && state != 'x' && state != 'K';
+ }
+
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId) {
ContentProviderRecord cpr;
@@ -10553,7 +10587,7 @@
}
}
- boolean providerRunning = cpr != null;
+ boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
if (providerRunning) {
cpi = cpr.info;
String msg;
@@ -10595,35 +10629,44 @@
}
}
- if (cpr.proc != null) {
- checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
- boolean success = updateOomAdjLocked(cpr.proc);
- maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
- checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
- if (DEBUG_PROVIDER) Slog.i(TAG_PROVIDER, "Adjust success: " + success);
- // NOTE: there is still a race here where a signal could be
- // pending on the process even though we managed to update its
- // adj level. Not sure what to do about this, but at least
- // the race is now smaller.
- if (!success) {
- // Uh oh... it looks like the provider's process
- // has been killed on us. We need to wait for a new
- // process to be started, and make sure its death
- // doesn't kill our process.
- Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString()
- + " is crashing; detaching " + r);
- boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
- checkTime(startTime, "getContentProviderImpl: before appDied");
- appDiedLocked(cpr.proc);
- checkTime(startTime, "getContentProviderImpl: after appDied");
- if (!lastRef) {
- // This wasn't the last ref our process had on
- // the provider... we have now been killed, bail.
- return null;
- }
- providerRunning = false;
- conn = null;
+ checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
+ final int verifiedAdj = cpr.proc.verifiedAdj;
+ boolean success = updateOomAdjLocked(cpr.proc);
+ // XXX things have changed so updateOomAdjLocked doesn't actually tell us
+ // if the process has been successfully adjusted. So to reduce races with
+ // it, we will check whether the process still exists. Note that this doesn't
+ // completely get rid of races with LMK killing the process, but should make
+ // them much smaller.
+ if (success && verifiedAdj != cpr.proc.setAdj && !isProcessAliveLocked(cpr.proc)) {
+ success = false;
+ }
+ maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
+ checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
+ if (DEBUG_PROVIDER) Slog.i(TAG_PROVIDER, "Adjust success: " + success);
+ // NOTE: there is still a race here where a signal could be
+ // pending on the process even though we managed to update its
+ // adj level. Not sure what to do about this, but at least
+ // the race is now smaller.
+ if (!success) {
+ // Uh oh... it looks like the provider's process
+ // has been killed on us. We need to wait for a new
+ // process to be started, and make sure its death
+ // doesn't kill our process.
+ Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString()
+ + " is crashing; detaching " + r);
+ boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
+ checkTime(startTime, "getContentProviderImpl: before appDied");
+ appDiedLocked(cpr.proc);
+ checkTime(startTime, "getContentProviderImpl: after appDied");
+ if (!lastRef) {
+ // This wasn't the last ref our process had on
+ // the provider... we have now been killed, bail.
+ return null;
}
+ providerRunning = false;
+ conn = null;
+ } else {
+ cpr.proc.verifiedAdj = cpr.proc.setAdj;
}
Binder.restoreCallingIdentity(origId);
@@ -10767,7 +10810,7 @@
checkTime(startTime, "getContentProviderImpl: looking for process record");
ProcessRecord proc = getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid, false);
- if (proc != null && proc.thread != null) {
+ if (proc != null && proc.thread != null && !proc.killed) {
if (DEBUG_PROVIDER) Slog.d(TAG_PROVIDER,
"Installing in existing process " + proc);
if (!proc.pubProviders.containsKey(cpi.name)) {
@@ -11476,11 +11519,15 @@
// Actually is sleeping or shutting down or whatever else in the future
// is an inactive state.
- public boolean isSleepingOrShuttingDown() {
- return isSleeping() || mShuttingDown;
+ boolean isSleepingOrShuttingDownLocked() {
+ return isSleepingLocked() || mShuttingDown;
}
- public boolean isSleeping() {
+ boolean isShuttingDownLocked() {
+ return mShuttingDown;
+ }
+
+ boolean isSleepingLocked() {
return mSleeping;
}
@@ -12850,7 +12897,7 @@
proc.notCachedSinceIdle = true;
proc.initialIdlePss = 0;
proc.nextPssTime = ProcessList.computeNextPssTime(proc.setProcState, true,
- mTestPssMode, isSleeping(), now);
+ mTestPssMode, isSleepingLocked(), now);
}
}
@@ -13498,13 +13545,13 @@
* @param parent activity related to the error, null if unknown
* @param subject line related to the error, null if absent
* @param report in long form describing the error, null if absent
- * @param logFile to include in the report, null if none
+ * @param dataFile text file to include in the report, null if none
* @param crashInfo giving an application stack trace, null if absent
*/
public void addErrorToDropBox(String eventType,
ProcessRecord process, String processName, ActivityRecord activity,
ActivityRecord parent, String subject,
- final String report, final File logFile,
+ final String report, final File dataFile,
final ApplicationErrorReport.CrashInfo crashInfo) {
// NOTE -- this must never acquire the ActivityManagerService lock,
// otherwise the watchdog may be prevented from resetting the system.
@@ -13559,20 +13606,24 @@
if (report != null) {
sb.append(report);
}
- if (logFile != null) {
+
+ String setting = Settings.Global.ERROR_LOGCAT_PREFIX + dropboxTag;
+ int lines = Settings.Global.getInt(mContext.getContentResolver(), setting, 0);
+ int maxDataFileSize = DROPBOX_MAX_SIZE - sb.length()
+ - lines * RESERVED_BYTES_PER_LOGCAT_LINE;
+
+ if (dataFile != null && maxDataFileSize > 0) {
try {
- sb.append(FileUtils.readTextFile(logFile, DROPBOX_MAX_SIZE,
+ sb.append(FileUtils.readTextFile(dataFile, maxDataFileSize,
"\n\n[[TRUNCATED]]"));
} catch (IOException e) {
- Slog.e(TAG, "Error reading " + logFile, e);
+ Slog.e(TAG, "Error reading " + dataFile, e);
}
}
if (crashInfo != null && crashInfo.stackTrace != null) {
sb.append(crashInfo.stackTrace);
}
- String setting = Settings.Global.ERROR_LOGCAT_PREFIX + dropboxTag;
- int lines = Settings.Global.getInt(mContext.getContentResolver(), setting, 0);
if (lines > 0) {
sb.append("\n");
@@ -16568,7 +16619,8 @@
&& capp.pid != MY_PID) {
capp.kill("depends on provider "
+ cpr.name.flattenToShortString()
- + " in dying proc " + (proc != null ? proc.processName : "??"), true);
+ + " in dying proc " + (proc != null ? proc.processName : "??")
+ + " (adj " + (proc != null ? proc.setAdj : "??") + ")", true);
}
} else if (capp.thread != null && conn.provider.provider != null) {
try {
@@ -17041,11 +17093,22 @@
// Cause the target app to be launched if necessary and its backup agent
// instantiated. The backup agent will invoke backupAgentCreated() on the
// activity manager to announce its creation.
- public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
- if (DEBUG_BACKUP) Slog.v(TAG_BACKUP,
- "bindBackupAgent: app=" + app + " mode=" + backupMode);
+ public boolean bindBackupAgent(String packageName, int backupMode, int userId) {
+ if (DEBUG_BACKUP) Slog.v(TAG, "bindBackupAgent: app=" + packageName + " mode=" + backupMode);
enforceCallingPermission("android.permission.CONFIRM_FULL_BACKUP", "bindBackupAgent");
+ IPackageManager pm = AppGlobals.getPackageManager();
+ ApplicationInfo app = null;
+ try {
+ app = pm.getApplicationInfo(packageName, 0, userId);
+ } catch (RemoteException e) {
+ // can't happen; package manager is process-local
+ }
+ if (app == null) {
+ Slog.w(TAG, "Unable to bind backup agent for " + packageName);
+ return false;
+ }
+
synchronized(this) {
// !!! TODO: currently no check here that we're already bound
BatteryStatsImpl.Uid.Pkg.Serv ss = null;
@@ -17752,6 +17815,14 @@
removeUriPermissionsForPackageLocked(ssp, userId, true);
removeTasksByPackageNameLocked(ssp, userId);
+
+ // Hide the "unsupported display" dialog if necessary.
+ if (mUnsupportedDisplaySizeDialog != null && ssp.equals(
+ mUnsupportedDisplaySizeDialog.getPackageName())) {
+ mUnsupportedDisplaySizeDialog.dismiss();
+ mUnsupportedDisplaySizeDialog = null;
+ }
+ mCompatModePackages.handlePackageUninstalledLocked(ssp);
mBatteryStatsService.notePackageUninstalled(ssp);
}
} else {
@@ -17823,6 +17894,21 @@
}
break;
}
+ case Intent.ACTION_PACKAGE_DATA_CLEARED:
+ {
+ Uri data = intent.getData();
+ String ssp;
+ if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
+ // Hide the "unsupported display" dialog if necessary.
+ if (mUnsupportedDisplaySizeDialog != null && ssp.equals(
+ mUnsupportedDisplaySizeDialog.getPackageName())) {
+ mUnsupportedDisplaySizeDialog.dismiss();
+ mUnsupportedDisplaySizeDialog = null;
+ }
+ mCompatModePackages.handlePackageDataClearedLocked(ssp);
+ }
+ break;
+ }
case Intent.ACTION_TIMEZONE_CHANGED:
// If this is the time zone changed action, queue up a message that will reset
// the timezone of all currently running processes. This message will get
@@ -17854,6 +17940,19 @@
// Apps should use JobScehduler to monitor for media provider changes.
Slog.w(TAG, action + " no longer allowed; dropping from "
+ UserHandle.formatUid(callingUid));
+ if (resultTo != null) {
+ final BroadcastQueue queue = broadcastQueueForIntent(intent);
+ try {
+ queue.performReceiveLocked(callerApp, resultTo, intent,
+ Activity.RESULT_CANCELED, null, null,
+ false, false, userId);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failure ["
+ + queue.mQueueName + "] sending broadcast result of "
+ + intent, e);
+
+ }
+ }
// Lie; we don't want to crash the app.
return ActivityManager.BROADCAST_SUCCESS;
}
@@ -18645,6 +18744,9 @@
final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
if (isDensityChange) {
+ // Reset the unsupported display size dialog.
+ mUiHandler.sendEmptyMessage(SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG);
+
killAllBackgroundProcessesExcept(Build.VERSION_CODES.N,
ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
}
@@ -19192,6 +19294,7 @@
}
boolean mayBeTop = false;
+ app.whitelistManager = false;
for (int is = app.services.size()-1;
is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
@@ -19232,8 +19335,6 @@
}
}
- app.whitelistManager = false;
-
for (int conni = s.connections.size()-1;
conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
@@ -19747,7 +19848,7 @@
if (memLowered || now > (app.lastStateTime+ProcessList.PSS_ALL_INTERVAL)) {
app.pssProcState = app.setProcState;
app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true,
- mTestPssMode, isSleeping(), now);
+ mTestPssMode, isSleepingLocked(), now);
mPendingPssProcesses.add(app);
}
}
@@ -19795,7 +19896,7 @@
}
}
return !processingBroadcasts
- && (isSleeping() || mStackSupervisor.allResumedActivitiesIdle());
+ && (isSleepingLocked() || mStackSupervisor.allResumedActivitiesIdle());
}
/**
@@ -20005,6 +20106,7 @@
"Set " + app.pid + " " + app.processName + " adj " + app.curAdj + ": "
+ app.adjType);
app.setAdj = app.curAdj;
+ app.verifiedAdj = ProcessList.INVALID_ADJ;
}
if (app.setSchedGroup != app.curSchedGroup) {
@@ -20086,7 +20188,7 @@
}
app.lastStateTime = now;
app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true,
- mTestPssMode, isSleeping(), now);
+ mTestPssMode, isSleepingLocked(), now);
if (DEBUG_PSS) Slog.d(TAG_PSS, "Process state change from "
+ ProcessList.makeProcStateString(app.setProcState) + " to "
+ ProcessList.makeProcStateString(app.curProcState) + " next pss in "
@@ -20097,7 +20199,7 @@
mTestPssMode)))) {
requestPssLocked(app, app.setProcState);
app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, false,
- mTestPssMode, isSleeping(), now);
+ mTestPssMode, isSleepingLocked(), now);
} else if (false && DEBUG_PSS) Slog.d(TAG_PSS,
"Not requesting PSS of " + app + ": next=" + (app.nextPssTime-now));
}
@@ -20623,7 +20725,7 @@
}
mLastMemoryLevel = memFactor;
mLastNumProcesses = mLruProcesses.size();
- boolean allChanged = mProcessStats.setMemFactorLocked(memFactor, !isSleeping(), now);
+ boolean allChanged = mProcessStats.setMemFactorLocked(memFactor, !isSleepingLocked(), now);
final int trackerMemFactor = mProcessStats.getMemFactorLocked();
if (memFactor != ProcessStats.ADJ_MEM_FACTOR_NORMAL) {
if (mLowRamStartTime == 0) {
@@ -21280,8 +21382,8 @@
}
@Override
- public void registerUserSwitchObserver(IUserSwitchObserver observer) {
- mUserController.registerUserSwitchObserver(observer);
+ public void registerUserSwitchObserver(IUserSwitchObserver observer, String name) {
+ mUserController.registerUserSwitchObserver(observer, name);
}
@Override
@@ -21555,6 +21657,16 @@
}
((PendingIntentRecord) target).setWhitelistDuration(duration);
}
+
+ @Override
+ public void updatePersistentConfigurationForUser(@NonNull Configuration values,
+ int userId) {
+ Preconditions.checkNotNull(values, "Configuration must not be null");
+ Preconditions.checkArgumentNonnegative(userId, "userId " + userId + " not supported");
+ synchronized (ActivityManagerService.this) {
+ updateConfigurationLocked(values, null, false, true, userId);
+ }
+ }
}
private final class SleepTokenImpl extends SleepToken {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 3ccac9e2..50b6c0c 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -444,10 +444,17 @@
return;
}
try {
+ // Make sure fontScale is always equal to global. For fullscreen apps, config is
+ // the shared EMPTY config, which has default fontScale of 1.0. We don't want it
+ // to be applied as an override config.
+ Configuration overrideConfig = new Configuration(config);
+ overrideConfig.fontScale = service.mConfiguration.fontScale;
+
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + this + " " +
- "reportToActivity=" + reportToActivity + " and config: " + config);
+ "reportToActivity=" + reportToActivity + " and config: " + overrideConfig);
+
app.thread.scheduleActivityConfigurationChanged(
- appToken, new Configuration(config), reportToActivity);
+ appToken, overrideConfig, reportToActivity);
} catch (RemoteException e) {
// If process died, whatever.
}
@@ -931,7 +938,7 @@
final ReferrerIntent rintent = new ReferrerIntent(intent, referrer);
boolean unsent = true;
if ((state == ActivityState.RESUMED
- || (service.isSleeping() && task.stack != null
+ || (service.isSleepingLocked() && task.stack != null
&& task.stack.topRunningActivityLocked() == this))
&& app != null && app.thread != null) {
try {
@@ -1150,13 +1157,6 @@
public void reportFullyDrawnLocked() {
final long curTime = SystemClock.uptimeMillis();
- // Normally launch time counts from the point when the activity is resumed, to when the
- // first window is drawn. However the activity could become visible before it is resumed,
- // due to some other activity in the same task being launched. In this case we still need
- // to report launch time to unblock ActivityStarter.startActivityMayWait().
- if (displayStartTime == 0 && task != null && task.isLaunching) {
- displayStartTime = curTime;
- }
if (displayStartTime != 0) {
reportLaunchTimeLocked(curTime);
}
@@ -1222,22 +1222,13 @@
//service.mUsageStatsService.noteLaunchTime(realActivity, (int)totalTime);
}
displayStartTime = 0;
- task.isLaunching = false;
stack.mLaunchStartTime = 0;
}
void windowsDrawnLocked() {
mStackSupervisor.mActivityMetricsLogger.notifyWindowsDrawn();
- final long curTime = SystemClock.uptimeMillis();
- // Normally launch time counts from the point when the activity is resumed, to when the
- // first window is drawn. However the activity could become visible before it is resumed,
- // due to some other activity in the same task being launched. In this case we still need
- // to report launch time to unblock ActivityStarter.startActivityMayWait().
- if (displayStartTime == 0 && task != null && task.isLaunching) {
- displayStartTime = curTime;
- }
if (displayStartTime != 0) {
- reportLaunchTimeLocked(curTime);
+ reportLaunchTimeLocked(SystemClock.uptimeMillis());
}
mStackSupervisor.sendWaitingVisibleReportLocked(this);
startTime = 0;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index d83a750..4059a67 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -825,7 +825,8 @@
* is the same as the given activity. Returns null if no such activity
* is found.
*/
- ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
+ ActivityRecord findActivityLocked(Intent intent, ActivityInfo info,
+ boolean compareIntentFilters) {
ComponentName cls = intent.getComponent();
if (info.targetActivity != null) {
cls = new ComponentName(info.packageName, info.targetActivity);
@@ -843,8 +844,16 @@
if (notCurrentUserTask && (r.info.flags & FLAG_SHOW_FOR_ALL_USERS) == 0) {
continue;
}
- if (!r.finishing && r.intent.getComponent().equals(cls) && r.userId == userId) {
- return r;
+ if (!r.finishing && r.userId == userId) {
+ if (compareIntentFilters) {
+ if (r.intent.filterEquals(intent)) {
+ return r;
+ }
+ } else {
+ if (r.intent.getComponent().equals(cls)) {
+ return r;
+ }
+ }
}
}
}
@@ -924,9 +933,6 @@
void setLaunchTime(ActivityRecord r) {
if (r.displayStartTime == 0) {
r.fullyDrawnStartTime = r.displayStartTime = SystemClock.uptimeMillis();
- if (r.task != null) {
- r.task.isLaunching = true;
- }
if (mLaunchStartTime == 0) {
startLaunchTraces(r.packageName);
mLaunchStartTime = mFullyDrawnStartTime = r.displayStartTime;
@@ -941,9 +947,6 @@
// Make sure that there is no activity waiting for this to launch.
if (mStackSupervisor.mWaitingActivityLaunched.isEmpty()) {
r.displayStartTime = r.fullyDrawnStartTime = 0;
- if (r.task != null) {
- r.task.isLaunching = false;
- }
} else {
mStackSupervisor.removeTimeoutsForActivityLocked(r);
mStackSupervisor.scheduleIdleTimeoutLocked(r);
@@ -1075,7 +1078,7 @@
if (mPausingActivity != null) {
Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity
+ " state=" + mPausingActivity.state);
- if (!mService.isSleeping()) {
+ if (!mService.isSleepingLocked()) {
// Avoid recursion among check for sleep and complete pause during sleeping.
// Because activity will be paused immediately after resume, just let pause
// be completed by the order of activity paused from clients.
@@ -1139,7 +1142,7 @@
// If we are not going to sleep, we want to ensure the device is
// awake until the next activity is started.
- if (!uiSleeping && !mService.isSleepingOrShuttingDown()) {
+ if (!uiSleeping && !mService.isSleepingOrShuttingDownLocked()) {
mStackSupervisor.acquireLaunchWakelock();
}
@@ -1292,7 +1295,7 @@
// We don't need to schedule another stop, we only need to let it happen.
prev.state = ActivityState.STOPPING;
} else if ((!prev.visible && !hasVisibleBehindActivity())
- || mService.isSleepingOrShuttingDown()) {
+ || mService.isSleepingOrShuttingDownLocked()) {
// If we were visible then resumeTopActivities will release resources before
// stopping.
addToStopping(prev, true /* immediate */);
@@ -1310,7 +1313,7 @@
if (resumeNext) {
final ActivityStack topStack = mStackSupervisor.getFocusedStack();
- if (!mService.isSleepingOrShuttingDown()) {
+ if (!mService.isSleepingOrShuttingDownLocked()) {
mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
} else {
mStackSupervisor.checkReadyForSleepLocked();
@@ -1398,6 +1401,7 @@
if (next.nowVisible) {
// We won't get a call to reportActivityVisibleLocked() so dismiss lockscreen now.
+ mStackSupervisor.reportActivityVisibleLocked(next);
mStackSupervisor.notifyActivityDrawnForKeyguard();
}
@@ -2195,7 +2199,7 @@
// If we are sleeping, and there is no resumed activity, and the top
// activity is paused, well that is the state we want.
- if (mService.isSleepingOrShuttingDown()
+ if (mService.isSleepingOrShuttingDownLocked()
&& mLastPausedActivity == next
&& mStackSupervisor.allPausedActivitiesComplete()) {
// Make sure we have executed any pending transitions, since there
@@ -2277,7 +2281,7 @@
// If the most recent activity was noHistory but was only stopped rather
// than stopped+finished because the device went to sleep, we need to make
// sure to finish it as we're making a new activity topmost.
- if (mService.isSleeping() && mLastNoHistoryActivity != null &&
+ if (mService.isSleepingLocked() && mLastNoHistoryActivity != null &&
!mLastNoHistoryActivity.finishing) {
if (DEBUG_STATES) Slog.d(TAG_STATES,
"no-history finish of " + mLastNoHistoryActivity + " on new resume");
@@ -2480,6 +2484,7 @@
System.identityHashCode(next), next.task.taskId, next.shortComponentName);
next.sleeping = false;
+ mService.showUnsupportedZoomDialogIfNeededLocked(next);
mService.showAskCompatModeDialogLocked(next);
next.app.pendingUiClean = true;
next.app.forceProcessStateUpTo(mService.mTopProcessState);
@@ -3211,7 +3216,7 @@
if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
if (!r.finishing) {
- if (!mService.isSleeping()) {
+ if (!mService.isSleepingLocked()) {
if (DEBUG_STATES) Slog.d(TAG_STATES, "no-history finish of " + r);
if (requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
"stop-no-history", false)) {
@@ -3243,7 +3248,7 @@
EventLogTags.writeAmStopActivity(
r.userId, System.identityHashCode(r), r.shortComponentName);
r.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags);
- if (mService.isSleepingOrShuttingDown()) {
+ if (mService.isSleepingOrShuttingDownLocked()) {
r.setSleeping(true);
}
Message msg = mHandler.obtainMessage(STOP_TIMEOUT_MSG, r);
@@ -4447,7 +4452,7 @@
}
}
if (updatedConfig) {
- // Ensure the resumed state of the focus activity if we updated the confiugaration of
+ // Ensure the resumed state of the focus activity if we updated the configuration of
// any activity.
mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
@@ -4467,6 +4472,15 @@
return true;
}
+ // TODO: We could probably make the condition below just check that the activity state is
+ // stopped, but also checking the sleep state for now to reduce change impact late in
+ // development cycle.
+ if (mService.isSleepingOrShuttingDownLocked() && r.state == ActivityState.STOPPED) {
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Skipping config check (stopped while sleeping): " + r);
+ return true;
+ }
+
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Ensuring correct configuration: " + r);
@@ -4727,6 +4741,8 @@
r.results = null;
r.newIntents = null;
}
+ mService.showUnsupportedZoomDialogIfNeededLocked(r);
+ mService.showAskCompatModeDialogLocked(r);
} else {
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
r.state = ActivityState.PAUSED;
@@ -5177,7 +5193,8 @@
r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId, r.info.configChanges,
task.voiceSession != null, r.mLaunchTaskBehind, bounds, task.mOverrideConfig,
- task.mResizeMode, r.isAlwaysFocusable(), task.isHomeTask());
+ task.mResizeMode, r.isAlwaysFocusable(), task.isHomeTask(),
+ r.appInfo.targetSdkVersion);
r.taskConfigOverride = task.mOverrideConfig;
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index f78fa8d..82668e4 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -111,6 +111,7 @@
import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
import static android.app.ActivityManager.RESIZE_MODE_FORCED;
import static android.app.ActivityManager.RESIZE_MODE_SYSTEM;
+import static android.app.ActivityManager.START_TASK_TO_FRONT;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
import static android.app.ActivityManager.StackId.FIRST_STATIC_STACK_ID;
@@ -1004,6 +1005,24 @@
}
}
+ void reportTaskToFrontNoLaunch(ActivityRecord r) {
+ boolean changed = false;
+ for (int i = mWaitingActivityLaunched.size() - 1; i >= 0; i--) {
+ WaitResult w = mWaitingActivityLaunched.remove(i);
+ if (w.who == null) {
+ changed = true;
+ // Set result to START_TASK_TO_FRONT so that startActivityMayWait() knows that
+ // the starting activity ends up moving another activity to front, and it should
+ // wait for this new activity to become visible instead.
+ // Do not modify other fields.
+ w.result = START_TASK_TO_FRONT;
+ }
+ }
+ if (changed) {
+ mService.notifyAll();
+ }
+ }
+
void reportActivityLaunchedLocked(boolean timeout, ActivityRecord r,
long thisTime, long totalTime) {
boolean changed = false;
@@ -1017,6 +1036,7 @@
}
w.thisTime = thisTime;
w.totalTime = totalTime;
+ // Do not modify w.result.
}
}
if (changed) {
@@ -1219,6 +1239,7 @@
PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY);
r.sleeping = false;
r.forceNewConfig = false;
+ mService.showUnsupportedZoomDialogIfNeededLocked(r);
mService.showAskCompatModeDialogLocked(r);
r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo);
ProfilerInfo profilerInfo = null;
@@ -2620,11 +2641,13 @@
return mTmpFindTaskResult.r;
}
- ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
+ ActivityRecord findActivityLocked(Intent intent, ActivityInfo info,
+ boolean compareIntentFilters) {
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityRecord ar = stacks.get(stackNdx).findActivityLocked(intent, info);
+ final ActivityRecord ar = stacks.get(stackNdx)
+ .findActivityLocked(intent, info, compareIntentFilters);
if (ar != null) {
return ar;
}
@@ -2709,7 +2732,7 @@
}
void checkReadyForSleepLocked() {
- if (!mService.isSleepingOrShuttingDown()) {
+ if (!mService.isSleepingOrShuttingDownLocked()) {
// Do not care.
return;
}
@@ -3027,8 +3050,9 @@
/** Checks whether the activity should be shown for current user. */
boolean okToShowLocked(ActivityRecord r) {
- return r != null && (isCurrentProfileLocked(r.userId)
- || (r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
+ return r != null && ((r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0
+ || (isCurrentProfileLocked(r.userId)
+ && !mService.mUserController.isUserStoppingOrShuttingDownLocked(r.userId)));
}
final ArrayList<ActivityRecord> processStoppingActivitiesLocked(boolean remove) {
@@ -3052,7 +3076,7 @@
mWindowManager.setAppVisibility(s.appToken, false);
}
}
- if ((!waitingVisible || mService.isSleepingOrShuttingDown()) && remove) {
+ if ((!waitingVisible || mService.isSleepingOrShuttingDownLocked()) && remove) {
if (DEBUG_STATES) Slog.v(TAG, "Ready to stop: " + s);
if (stops == null) {
stops = new ArrayList<>();
@@ -3776,7 +3800,7 @@
} break;
case SLEEP_TIMEOUT_MSG: {
synchronized (mService) {
- if (mService.isSleepingOrShuttingDown()) {
+ if (mService.isSleepingOrShuttingDownLocked()) {
Slog.w(TAG, "Sleep timeout! Sleeping now.");
mSleepTimeout = true;
checkReadyForSleepLocked();
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 793f411..77b450f 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -555,6 +555,13 @@
return;
}
+ // We're waiting for an activity launch to finish, but that activity simply
+ // brought another activity to front. Let startActivityMayWait() know about
+ // this, so it waits for the new activity to become visible instead.
+ if (result == START_TASK_TO_FRONT && !mSupervisor.mWaitingActivityLaunched.isEmpty()) {
+ mSupervisor.reportTaskToFrontNoLaunch(mStartActivity);
+ }
+
int startedActivityStackId = INVALID_STACK_ID;
if (r.task != null && r.task.stack != null) {
startedActivityStackId = r.task.stack.mStackId;
@@ -842,8 +849,13 @@
mService.wait();
} catch (InterruptedException e) {
}
- } while (!outResult.timeout && outResult.who == null);
- } else if (res == START_TASK_TO_FRONT) {
+ } while (outResult.result != START_TASK_TO_FRONT
+ && !outResult.timeout && outResult.who == null);
+ if (outResult.result == START_TASK_TO_FRONT) {
+ res = START_TASK_TO_FRONT;
+ }
+ }
+ if (res == START_TASK_TO_FRONT) {
ActivityRecord r = stack.topRunningActivityLocked();
if (r.nowVisible && r.state == RESUMED) {
outResult.timeout = false;
@@ -1438,11 +1450,12 @@
if (mLaunchSingleInstance) {
// There can be one and only one instance of single instance activity in the
// history, and it is always in its own unique task, so we do a special search.
- intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info);
+ intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info, false);
} else if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
// For the launch adjacent case we only want to put the activity in an existing
// task if the activity already exists in the history.
- intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info);
+ intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info,
+ !mLaunchSingleTask);
} else {
// Otherwise find the best task to put the activity in.
intentActivity = mSupervisor.findTaskLocked(mStartActivity);
@@ -1494,14 +1507,23 @@
intentActivity.task, mNoAnimation, mOptions,
mStartActivity.appTimeTracker, "bringingFoundTaskToFront");
mMovedToFront = true;
- } else if ((launchStack.mStackId == DOCKED_STACK_ID
- || launchStack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID)
- && (mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
- // If we want to launch adjacent and mTargetStack is not the computed
- // launch stack - move task to top of computed stack.
- mSupervisor.moveTaskToStackLocked(intentActivity.task.taskId,
- launchStack.mStackId, ON_TOP, FORCE_FOCUS, "launchToSide",
- ANIMATE);
+ } else if (launchStack.mStackId == DOCKED_STACK_ID
+ || launchStack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
+ if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
+ // If we want to launch adjacent and mTargetStack is not the computed
+ // launch stack - move task to top of computed stack.
+ mSupervisor.moveTaskToStackLocked(intentActivity.task.taskId,
+ launchStack.mStackId, ON_TOP, FORCE_FOCUS, "launchToSide",
+ ANIMATE);
+ } else {
+ // TODO: This should be reevaluated in MW v2.
+ // We choose to move task to front instead of launching it adjacent
+ // when specific stack was requested explicitly and it appeared to be
+ // adjacent stack, but FLAG_ACTIVITY_LAUNCH_ADJACENT was not set.
+ mTargetStack.moveTaskToFrontLocked(intentActivity.task, mNoAnimation,
+ mOptions, mStartActivity.appTimeTracker,
+ "bringToFrontInsteadOfAdjacentLaunch");
+ }
mMovedToFront = true;
}
mOptions = null;
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 88645c1e..a279290 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -456,7 +456,7 @@
}
}
- private void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
+ void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
Intent intent, int resultCode, String data, Bundle extras,
boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
// Send the intent to the receiver asynchronously using one-way binder calls.
diff --git a/services/core/java/com/android/server/am/CompatModePackages.java b/services/core/java/com/android/server/am/CompatModePackages.java
index 26264e5..a54df4b 100644
--- a/services/core/java/com/android/server/am/CompatModePackages.java
+++ b/services/core/java/com/android/server/am/CompatModePackages.java
@@ -57,6 +57,8 @@
public static final int COMPAT_FLAG_DONT_ASK = 1<<0;
// Compatibility state: compatibility mode is enabled.
public static final int COMPAT_FLAG_ENABLED = 1<<1;
+ // Unsupported zoom state: don't warn the user about unsupported zoom mode.
+ public static final int UNSUPPORTED_ZOOM_FLAG_DONT_NOTIFY = 1<<2;
private final HashMap<String, Integer> mPackages = new HashMap<String, Integer>();
@@ -147,6 +149,24 @@
return flags != null ? flags : 0;
}
+ public void handlePackageDataClearedLocked(String packageName) {
+ // User has explicitly asked to clear all associated data.
+ removePackage(packageName);
+ }
+
+ public void handlePackageUninstalledLocked(String packageName) {
+ // Clear settings when app is uninstalled since this is an explicit
+ // signal from the user to remove the app and all associated data.
+ removePackage(packageName);
+ }
+
+ private void removePackage(String packageName) {
+ if (mPackages.containsKey(packageName)) {
+ mPackages.remove(packageName);
+ scheduleWrite();
+ }
+ }
+
public void handlePackageAddedLocked(String packageName, boolean updated) {
ApplicationInfo ai = null;
try {
@@ -165,13 +185,17 @@
// any current settings for it.
if (!mayCompat && mPackages.containsKey(packageName)) {
mPackages.remove(packageName);
- mHandler.removeMessages(MSG_WRITE);
- Message msg = mHandler.obtainMessage(MSG_WRITE);
- mHandler.sendMessageDelayed(msg, 10000);
+ scheduleWrite();
}
}
}
+ private void scheduleWrite() {
+ mHandler.removeMessages(MSG_WRITE);
+ Message msg = mHandler.obtainMessage(MSG_WRITE);
+ mHandler.sendMessageDelayed(msg, 10000);
+ }
+
public CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) {
CompatibilityInfo ci = new CompatibilityInfo(ai, mService.mConfiguration.screenLayout,
mService.mConfiguration.smallestScreenWidthDp,
@@ -207,6 +231,10 @@
return (getPackageFlags(packageName)&COMPAT_FLAG_DONT_ASK) == 0;
}
+ public boolean getPackageNotifyUnsupportedZoomLocked(String packageName) {
+ return (getPackageFlags(packageName)&UNSUPPORTED_ZOOM_FLAG_DONT_NOTIFY) == 0;
+ }
+
public void setFrontActivityAskCompatModeLocked(boolean ask) {
ActivityRecord r = mService.getFocusedStack().topRunningActivityLocked();
if (r != null) {
@@ -223,9 +251,21 @@
} else {
mPackages.remove(packageName);
}
- mHandler.removeMessages(MSG_WRITE);
- Message msg = mHandler.obtainMessage(MSG_WRITE);
- mHandler.sendMessageDelayed(msg, 10000);
+ scheduleWrite();
+ }
+ }
+
+ public void setPackageNotifyUnsupportedZoomLocked(String packageName, boolean notify) {
+ final int curFlags = getPackageFlags(packageName);
+ final int newFlags = notify ? (curFlags&~UNSUPPORTED_ZOOM_FLAG_DONT_NOTIFY) :
+ (curFlags|UNSUPPORTED_ZOOM_FLAG_DONT_NOTIFY);
+ if (curFlags != newFlags) {
+ if (newFlags != 0) {
+ mPackages.put(packageName, newFlags);
+ } else {
+ mPackages.remove(packageName);
+ }
+ scheduleWrite();
}
}
@@ -321,9 +361,7 @@
// Need to get compatibility info in new state.
ci = compatibilityInfoForPackageLocked(ai);
- mHandler.removeMessages(MSG_WRITE);
- Message msg = mHandler.obtainMessage(MSG_WRITE);
- mHandler.sendMessageDelayed(msg, 10000);
+ scheduleWrite();
final ActivityStack stack = mService.getFocusedStack();
ActivityRecord starting = stack.restartPackage(packageName);
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 691fd2a..8911a3e 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -75,6 +75,7 @@
ProcessState baseProcessTracker;
BatteryStatsImpl.Uid.Proc curProcBatteryStats;
int pid; // The process of this application; 0 if none
+ String procStatFile; // path to /proc/<pid>/stat
int[] gids; // The gids this process was launched with
String requiredAbi; // The ABI this process was launched with
String instructionSet; // The instruction set this process was launched with
@@ -93,6 +94,7 @@
int setRawAdj; // Last set OOM unlimited adjustment for this process
int curAdj; // Current OOM adjustment for this process
int setAdj; // Last set OOM adjustment for this process
+ int verifiedAdj; // The last adjustment that was verified as actually being set
int curSchedGroup; // Currently desired scheduling class
int setSchedGroup; // Last set to background scheduling class
int trimMemoryLevel; // Last selected memory trimming level
@@ -441,7 +443,7 @@
pkgList.put(_info.packageName, new ProcessStats.ProcessStateHolder(_info.versionCode));
maxAdj = ProcessList.UNKNOWN_ADJ;
curRawAdj = setRawAdj = ProcessList.INVALID_ADJ;
- curAdj = setAdj = ProcessList.INVALID_ADJ;
+ curAdj = setAdj = verifiedAdj = ProcessList.INVALID_ADJ;
persistent = false;
removed = false;
lastStateTime = lastPssTime = nextPssTime = SystemClock.uptimeMillis();
@@ -449,6 +451,7 @@
public void setPid(int _pid) {
pid = _pid;
+ procStatFile = null;
shortStringName = null;
stringName = null;
}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index c84aaac..3f6db99 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -154,7 +154,6 @@
long lastActiveTime; // Last time this task was active, including sleep.
boolean inRecents; // Actually in the recents list?
boolean isAvailable; // Is the activity available to be launched?
- boolean isLaunching; // Is an activity in this task launching?
boolean rootWasReset; // True if the intent at the root of the task had
// the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
boolean autoRemoveRecents; // If true, we should automatically remove the task from
diff --git a/services/core/java/com/android/server/am/UnsupportedDisplaySizeDialog.java b/services/core/java/com/android/server/am/UnsupportedDisplaySizeDialog.java
new file mode 100644
index 0000000..501cd6b
--- /dev/null
+++ b/services/core/java/com/android/server/am/UnsupportedDisplaySizeDialog.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2011 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.am;
+
+import com.android.internal.R;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.CheckBox;
+
+public class UnsupportedDisplaySizeDialog {
+ private final AlertDialog mDialog;
+ private final String mPackageName;
+
+ public UnsupportedDisplaySizeDialog(final ActivityManagerService service, Context context,
+ ApplicationInfo appInfo) {
+ mPackageName = appInfo.packageName;
+
+ final PackageManager pm = context.getPackageManager();
+ final CharSequence label = appInfo.loadSafeLabel(pm);
+ final CharSequence message = context.getString(
+ R.string.unsupported_display_size_message, label);
+
+ mDialog = new AlertDialog.Builder(context)
+ .setPositiveButton(R.string.ok, null)
+ .setMessage(message)
+ .setView(R.layout.unsupported_display_size_dialog_content)
+ .create();
+
+ // Ensure the content view is prepared.
+ mDialog.create();
+
+ final Window window = mDialog.getWindow();
+ window.setType(WindowManager.LayoutParams.TYPE_PHONE);
+
+ // DO NOT MODIFY. Used by CTS to verify the dialog is displayed.
+ window.getAttributes().setTitle("UnsupportedDisplaySizeDialog");
+
+ final CheckBox alwaysShow = (CheckBox) mDialog.findViewById(R.id.ask_checkbox);
+ alwaysShow.setChecked(true);
+ alwaysShow.setOnCheckedChangeListener((buttonView, isChecked) -> {
+ synchronized (service) {
+ service.mCompatModePackages.setPackageNotifyUnsupportedZoomLocked(
+ mPackageName, isChecked);
+ }
+ });
+ }
+
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ public void show() {
+ mDialog.show();
+ }
+
+ public void dismiss() {
+ mDialog.dismiss();
+ }
+}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 2375d7a..6b44f14 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -76,6 +76,7 @@
import android.os.UserManagerInternal;
import android.os.storage.IMountService;
import android.os.storage.StorageManager;
+import android.util.ArraySet;
import android.util.IntArray;
import android.util.Pair;
import android.util.Slog;
@@ -86,6 +87,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.Preconditions;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
import com.android.server.pm.UserManagerService;
@@ -151,9 +153,9 @@
= new RemoteCallbackList<>();
/**
- * Currently active user switch.
+ * Currently active user switch callbacks.
*/
- Object mCurUserSwitchCallback;
+ private volatile ArraySet<String> mCurWaitingUserSwitchCallbacks;
private volatile UserManagerService mUserManager;
@@ -1040,7 +1042,8 @@
void timeoutUserSwitch(UserState uss, int oldUserId, int newUserId) {
synchronized (mService) {
- Slog.wtf(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId);
+ Slog.wtf(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId
+ + ". Observers that didn't send results: " + mCurWaitingUserSwitchCallbacks);
sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
}
}
@@ -1049,28 +1052,36 @@
Slog.d(TAG, "Dispatch onUserSwitching oldUser #" + oldUserId + " newUser #" + newUserId);
final int observerCount = mUserSwitchObservers.beginBroadcast();
if (observerCount > 0) {
- final IRemoteCallback callback = new IRemoteCallback.Stub() {
- int mCount = 0;
- @Override
- public void sendResult(Bundle data) throws RemoteException {
- synchronized (mService) {
- if (mCurUserSwitchCallback == this) {
- mCount++;
- if (mCount == observerCount) {
- sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
- }
- }
- }
- }
- };
+ final ArraySet<String> curWaitingUserSwitchCallbacks = new ArraySet<>();
synchronized (mService) {
uss.switching = true;
- mCurUserSwitchCallback = callback;
+ mCurWaitingUserSwitchCallbacks = curWaitingUserSwitchCallbacks;
}
for (int i = 0; i < observerCount; i++) {
try {
- mUserSwitchObservers.getBroadcastItem(i).onUserSwitching(
- newUserId, callback);
+ // Prepend with unique prefix to guarantee that keys are unique
+ final String name = "#" + i + " " + mUserSwitchObservers.getBroadcastCookie(i);
+ synchronized (mService) {
+ curWaitingUserSwitchCallbacks.add(name);
+ }
+ final IRemoteCallback callback = new IRemoteCallback.Stub() {
+ @Override
+ public void sendResult(Bundle data) throws RemoteException {
+ synchronized (mService) {
+ // Early return if this session is no longer valid
+ if (curWaitingUserSwitchCallbacks
+ != mCurWaitingUserSwitchCallbacks) {
+ return;
+ }
+ curWaitingUserSwitchCallbacks.remove(name);
+ // Continue switching if all callbacks have been notified
+ if (curWaitingUserSwitchCallbacks.isEmpty()) {
+ sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
+ }
+ }
+ }
+ };
+ mUserSwitchObservers.getBroadcastItem(i).onUserSwitching(newUserId, callback);
} catch (RemoteException e) {
}
}
@@ -1083,7 +1094,7 @@
}
void sendContinueUserSwitchLocked(UserState uss, int oldUserId, int newUserId) {
- mCurUserSwitchCallback = null;
+ mCurWaitingUserSwitchCallbacks = null;
mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
mHandler.sendMessage(mHandler.obtainMessage(ActivityManagerService.CONTINUE_USER_SWITCH_MSG,
oldUserId, newUserId, uss));
@@ -1248,7 +1259,8 @@
? getCurrentUserIdLocked(): userId;
}
- void registerUserSwitchObserver(IUserSwitchObserver observer) {
+ void registerUserSwitchObserver(IUserSwitchObserver observer, String name) {
+ Preconditions.checkNotNull(name, "Observer name cannot be null");
if (mService.checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
!= PackageManager.PERMISSION_GRANTED) {
final String msg = "Permission Denial: registerUserSwitchObserver() from pid="
@@ -1258,8 +1270,7 @@
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
-
- mUserSwitchObservers.register(observer);
+ mUserSwitchObservers.register(observer, name);
}
void unregisterUserSwitchObserver(IUserSwitchObserver observer) {
@@ -1336,6 +1347,15 @@
return mStartedUserArray;
}
+ boolean isUserStoppingOrShuttingDownLocked(int userId) {
+ UserState state = getStartedUserStateLocked(userId);
+ if (state == null) {
+ return false;
+ }
+ return state.state == UserState.STATE_STOPPING
+ || state.state == UserState.STATE_SHUTDOWN;
+ }
+
boolean isUserRunningLocked(int userId, int flags) {
UserState state = getStartedUserStateLocked(userId);
if (state == null) {
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 9220aa3..01b2393 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -394,18 +394,9 @@
for (int i=0; i<numCalls; i++) {
ObserverCall oc = calls.get(i);
try {
- // If the uri does not belong to the same user as the observer: we must add
- // the userId to the uri. Otherewise the observer would think the uri belongs
- // to his user.
- final Uri tempUri;
- if (oc.mObserverUserId != userHandle) {
- tempUri = ContentProvider.maybeAddUserId(uri, userHandle);
- } else {
- tempUri = uri;
- }
- oc.mObserver.onChange(oc.mSelfChange, tempUri, userHandle);
+ oc.mObserver.onChange(oc.mSelfChange, uri, userHandle);
if (DEBUG) Slog.d(TAG, "Notified " + oc.mObserver + " of " + "update at "
- + tempUri);
+ + uri);
} catch (RemoteException ex) {
synchronized (mRootNode) {
Log.w(TAG, "Found dead observer, removing");
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 493fc4a..39ddc3a 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -1355,7 +1355,11 @@
operation.extras.remove(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF);
}
- if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false)) {
+ if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false)
+ && !syncResult.syncAlreadyInProgress) {
+ // syncAlreadyInProgress flag is set by AbstractThreadedSyncAdapter. The sync adapter
+ // has no way of knowing that a sync error occured. So we DO retry if the error is
+ // syncAlreadyInProgress.
if (isLoggable) {
Log.d(TAG, "not retrying sync operation because SYNC_EXTRAS_DO_NOT_RETRY was specified "
+ operation);
@@ -2445,6 +2449,10 @@
if (op.isPeriodic) {
scheduleSyncOperationH(op.createOneTimeSyncOperation(), delay);
} else {
+ // mSyncJobService.callJobFinished is async, so cancel the job to ensure we don't
+ // find the this job in the pending jobs list while looking for duplicates
+ // before scheduling it at a later time.
+ getJobScheduler().cancel(op.jobId);
scheduleSyncOperationH(op, delay);
}
}
@@ -2886,6 +2894,14 @@
String historyMessage;
int downstreamActivity;
int upstreamActivity;
+
+ if (!syncOperation.isPeriodic) {
+ // mSyncJobService.jobFinidhed is async, we need to ensure that this job is
+ // removed from JobScheduler's pending jobs list before moving forward and
+ // potentially rescheduling all pending jobs to respect new backoff values.
+ getJobScheduler().cancel(syncOperation.jobId);
+ }
+
if (syncResult != null) {
if (isLoggable) {
Slog.v(TAG, "runSyncFinishedOrCanceled [finished]: "
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 1f6616e..a783fa2 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -20,6 +20,7 @@
import com.android.internal.util.DumpUtils;
import com.android.server.FgThread;
+import com.android.server.LocalServices;
import com.android.server.SystemService;
import android.Manifest;
@@ -32,6 +33,8 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ServiceInfo;
+import android.database.ContentObserver;
+import android.hardware.input.InputManagerInternal;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
@@ -111,11 +114,16 @@
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ writePulseGestureEnabled();
synchronized (mLock) {
stopDreamLocked(false /*immediate*/);
}
}
}, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.DOZE_ENABLED), false,
+ mDozeEnabledObserver, UserHandle.USER_ALL);
+ writePulseGestureEnabled();
}
}
@@ -414,6 +422,12 @@
}
}
+ private void writePulseGestureEnabled() {
+ ComponentName name = getDozeComponent();
+ boolean dozeEnabled = validateDream(name);
+ LocalServices.getService(InputManagerInternal.class).setPulseGestureEnabled(dozeEnabled);
+ }
+
private static String componentsToString(ComponentName[] componentNames) {
StringBuilder names = new StringBuilder();
if (componentNames != null) {
@@ -450,6 +464,13 @@
}
};
+ private final ContentObserver mDozeEnabledObserver = new ContentObserver(null) {
+ @Override
+ public void onChange(boolean selfChange) {
+ writePulseGestureEnabled();
+ }
+ };
+
/**
* Handler for asynchronous operations performed by the dream manager.
* Ensures operations to {@link DreamController} are single-threaded.
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index cc556c7..14e4bc6 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -1013,7 +1013,7 @@
public void onForegroundProfileSwitch(int newProfileId) {
// Ignore.
}
- });
+ }, TAG);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to listen for user switching event" ,e);
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index aa1d73f..74095ac 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -18,7 +18,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.Build;
import android.os.LocaleList;
+import android.util.Log;
import android.view.Display;
import com.android.internal.inputmethod.InputMethodSubtypeHandle;
import com.android.internal.os.SomeArgs;
@@ -98,8 +100,11 @@
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.FileReader;
+import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -109,6 +114,7 @@
import java.util.List;
import java.util.Locale;
+import libcore.io.IoUtils;
import libcore.io.Streams;
import libcore.util.Objects;
@@ -136,6 +142,8 @@
private final Context mContext;
private final InputManagerHandler mHandler;
+ private final File mDoubleTouchGestureEnableFile;
+
private WindowManagerCallbacks mWindowManagerCallbacks;
private WiredAccessoryCallbacks mWiredAccessoryCallbacks;
private boolean mSystemReady;
@@ -301,6 +309,11 @@
+ mUseDevInputEventForAudioJack);
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
+ String doubleTouchGestureEnablePath = context.getResources().getString(
+ R.string.config_doubleTouchGestureEnableFile);
+ mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
+ new File(doubleTouchGestureEnablePath);
+
LocalServices.addService(InputManagerInternal.class, new LocalService());
}
@@ -2279,5 +2292,20 @@
public void toggleCapsLock(int deviceId) {
nativeToggleCapsLock(mPtr, deviceId);
}
+
+ @Override
+ public void setPulseGestureEnabled(boolean enabled) {
+ if (mDoubleTouchGestureEnableFile != null) {
+ FileWriter writer = null;
+ try {
+ writer = new FileWriter(mDoubleTouchGestureEnableFile);
+ writer.write(enabled ? "1" : "0");
+ } catch (IOException e) {
+ Log.wtf(TAG, "Unable to setPulseGestureEnabled", e);
+ } finally {
+ IoUtils.closeQuietly(writer);
+ }
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 27b3aa2..8589de1 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -692,8 +692,13 @@
boolean active = mPendingJobs.size() > 0;
if (mPendingJobs.size() <= 0) {
for (int i=0; i<mActiveServices.size(); i++) {
- JobServiceContext jsc = mActiveServices.get(i);
- if (jsc.getRunningJob() != null) {
+ final JobServiceContext jsc = mActiveServices.get(i);
+ final JobStatus job = jsc.getRunningJob();
+ if (job != null
+ && (job.getJob().getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) == 0
+ && !job.dozeWhitelisted) {
+ // We will report active if we have a job running and it is not an exception
+ // due to being in the foreground or whitelisted.
active = true;
break;
}
diff --git a/services/core/java/com/android/server/job/controllers/AppIdleController.java b/services/core/java/com/android/server/job/controllers/AppIdleController.java
index a23af35..2dbecbd 100644
--- a/services/core/java/com/android/server/job/controllers/AppIdleController.java
+++ b/services/core/java/com/android/server/job/controllers/AppIdleController.java
@@ -142,8 +142,11 @@
UserHandle.formatUid(pw, jobStatus.getSourceUid());
pw.print(": ");
pw.print(jobStatus.getSourcePackageName());
- pw.print(", runnable=");
- pw.println((jobStatus.satisfiedConstraints&JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0);
+ if ((jobStatus.satisfiedConstraints&JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0) {
+ pw.println(" RUNNABLE");
+ } else {
+ pw.println(" WAITING");
+ }
}
});
}
diff --git a/services/core/java/com/android/server/job/controllers/ContentObserverController.java b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
index 26660e8..9dce070 100644
--- a/services/core/java/com/android/server/job/controllers/ContentObserverController.java
+++ b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
@@ -57,7 +57,7 @@
private static volatile ContentObserverController sController;
final private List<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
- ArrayMap<Uri, ObserverInstance> mObservers = new ArrayMap<>();
+ ArrayMap<JobInfo.TriggerContentUri, ObserverInstance> mObservers = new ArrayMap<>();
final Handler mHandler;
public static ContentObserverController get(JobSchedulerService taskManagerService) {
@@ -253,10 +253,10 @@
final JobInfo.TriggerContentUri[] uris = jobStatus.getJob().getTriggerContentUris();
if (uris != null) {
for (JobInfo.TriggerContentUri uri : uris) {
- ObserverInstance obs = mObservers.get(uri.getUri());
+ ObserverInstance obs = mObservers.get(uri);
if (obs == null) {
obs = new ObserverInstance(mHandler, uri.getUri());
- mObservers.put(uri.getUri(), obs);
+ mObservers.put(uri, obs);
mContext.getContentResolver().registerContentObserver(
uri.getUri(),
(uri.getFlags() &
@@ -316,7 +316,7 @@
obs.mJobs.remove(this);
if (obs.mJobs.size() == 0) {
mContext.getContentResolver().unregisterContentObserver(obs);
- mObservers.remove(obs.mUri);
+ mObservers.remove(obs);
}
}
}
@@ -355,7 +355,10 @@
continue;
}
pw.print(" ");
- pw.print(mObservers.keyAt(i));
+ JobInfo.TriggerContentUri trigger = mObservers.keyAt(i);
+ pw.print(trigger.getUri());
+ pw.print(" 0x");
+ pw.print(Integer.toHexString(trigger.getFlags()));
pw.print(" (");
pw.print(System.identityHashCode(obs));
pw.println("):");
diff --git a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
index bf1297f..f7706d7 100644
--- a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
+++ b/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
@@ -157,8 +157,9 @@
}
private void updateTaskStateLocked(JobStatus task) {
- boolean enableTask = !mDeviceIdleMode || isWhitelistedLocked(task);
- task.setDeviceNotDozingConstraintSatisfied(enableTask);
+ final boolean whitelisted = isWhitelistedLocked(task);
+ final boolean enableTask = !mDeviceIdleMode || whitelisted;
+ task.setDeviceNotDozingConstraintSatisfied(enableTask, whitelisted);
}
@Override
@@ -186,9 +187,13 @@
UserHandle.formatUid(pw, jobStatus.getSourceUid());
pw.print(": ");
pw.print(jobStatus.getSourcePackageName());
- pw.print(", runnable=");
- pw.println((jobStatus.satisfiedConstraints
- & JobStatus.CONSTRAINT_DEVICE_NOT_DOZING) != 0);
+ pw.print((jobStatus.satisfiedConstraints
+ & JobStatus.CONSTRAINT_DEVICE_NOT_DOZING) != 0
+ ? " RUNNABLE" : " WAITING");
+ if (jobStatus.dozeWhitelisted) {
+ pw.print(" WHITELISTED");
+ }
+ pw.println();
}
});
}
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index ded7a2f..552c990 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -103,6 +103,9 @@
final int requiredConstraints;
int satisfiedConstraints = 0;
+ // Set to true if doze constraint was satisfied due to app being whitelisted.
+ public boolean dozeWhitelisted;
+
// These are filled in by controllers when preparing for execution.
public ArraySet<Uri> changedUris;
public ArraySet<String> changedAuthorities;
@@ -403,7 +406,8 @@
return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state);
}
- boolean setDeviceNotDozingConstraintSatisfied(boolean state) {
+ boolean setDeviceNotDozingConstraintSatisfied(boolean state, boolean whitelisted) {
+ dozeWhitelisted = whitelisted;
return setConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING, state);
}
@@ -651,6 +655,9 @@
pw.print(prefix); pw.print("Unsatisfied constraints:");
dumpConstraints(pw, (requiredConstraints & ~satisfiedConstraints));
pw.println();
+ if (dozeWhitelisted) {
+ pw.print(prefix); pw.println("Doze whitelisted: true");
+ }
}
if (changedAuthorities != null) {
pw.print(prefix); pw.println("Changed authorities:");
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 6b916be..173f76f 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -899,6 +899,7 @@
// hold wake lock while task runs
mWakeLock.acquire();
+ Log.i(TAG, "WakeLock acquired by handleInjectNtpTime()");
AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
@Override
public void run() {
@@ -951,6 +952,7 @@
// release wake lock held by task
mWakeLock.release();
+ Log.i(TAG, "WakeLock released by handleInjectNtpTime()");
}
});
}
@@ -969,6 +971,7 @@
// hold wake lock while task runs
mWakeLock.acquire();
+ Log.i(TAG, "WakeLock acquired by handleDownloadXtraData()");
AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
@Override
public void run() {
@@ -991,6 +994,7 @@
// release wake lock held by task
mWakeLock.release();
+ Log.i(TAG, "WakeLock released by handleDownloadXtraData()");
}
});
}
@@ -1192,7 +1196,7 @@
}
if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest);
- if (mProviderRequest.reportLocation && !mDisableGps) {
+ if (mProviderRequest.reportLocation && !mDisableGps && isEnabled()) {
// update client uids
updateClientUids(mWorkSource);
@@ -2040,6 +2044,7 @@
// note that this assumes the message will not be removed from the queue before
// it is handled (otherwise the wake lock would be leaked).
mWakeLock.acquire();
+ Log.i(TAG, "WakeLock acquired by sendMessage(" + message + ", " + arg + ", " + obj + ")");
mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
}
@@ -2099,6 +2104,8 @@
if (msg.arg2 == 1) {
// wakelock was taken for this message, release it
mWakeLock.release();
+ Log.i(TAG, "WakeLock released by handleMessage(" + message + ", " + msg.arg1 + ", "
+ + msg.obj + ")");
}
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 67cd7c3..6648d1e 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -89,6 +89,7 @@
import static org.xmlpull.v1.XmlPullParser.START_TAG;
import android.Manifest;
+import android.annotation.IntDef;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.AppOpsManager;
@@ -162,6 +163,7 @@
import android.util.Xml;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.ArrayUtils;
@@ -187,6 +189,8 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
@@ -199,6 +203,26 @@
* Derives active rules by combining a given policy with other system status,
* and delivers to listeners, such as {@link ConnectivityManager}, for
* enforcement.
+ *
+ * <p>
+ * This class uses 2-3 locks to synchronize state:
+ * <ul>
+ * <li>{@code mUidRulesFirstLock}: used to guard state related to individual UIDs (such as firewall
+ * rules).
+ * <li>{@code mNetworkPoliciesSecondLock}: used to guard state related to network interfaces (such
+ * as network policies).
+ * <li>{@code allLocks}: not a "real" lock, but an indication (through @GuardedBy) that all locks
+ * must be held.
+ * </ul>
+ *
+ * <p>
+ * As such, methods that require synchronization have the following prefixes:
+ * <ul>
+ * <li>{@code UL()}: require the "UID" lock ({@code mUidRulesFirstLock}).
+ * <li>{@code NL()}: require the "Network" lock ({@code mNetworkPoliciesSecondLock}).
+ * <li>{@code AL()}: require all locks, which must be obtained in order ({@code mUidRulesFirstLock}
+ * first, then {@code mNetworkPoliciesSecondLock}, then {@code mYetAnotherGuardThirdLock}, etc..
+ * </ul>
*/
public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
static final String TAG = "NetworkPolicy";
@@ -282,13 +306,16 @@
private PowerManagerInternal mPowerManagerInternal;
private IDeviceIdleController mDeviceIdleController;
- final Object mRulesLock = new Object();
+ // See main javadoc for instructions on how to use these locks.
+ final Object mUidRulesFirstLock = new Object();
+ final Object mNetworkPoliciesSecondLock = new Object();
- volatile boolean mSystemReady;
- volatile boolean mScreenOn;
- volatile boolean mRestrictBackground;
- volatile boolean mRestrictPower;
- volatile boolean mDeviceIdleMode;
+ @GuardedBy("allLocks") volatile boolean mSystemReady;
+
+ @GuardedBy("mUidRulesFirstLock") volatile boolean mScreenOn;
+ @GuardedBy("mUidRulesFirstLock") volatile boolean mRestrictBackground;
+ @GuardedBy("mUidRulesFirstLock") volatile boolean mRestrictPower;
+ @GuardedBy("mUidRulesFirstLock") volatile boolean mDeviceIdleMode;
private final boolean mSuppressDefaultPolicy;
@@ -298,15 +325,19 @@
final ArrayMap<NetworkPolicy, String[]> mNetworkRules = new ArrayMap<>();
/** Defined UID policies. */
- final SparseIntArray mUidPolicy = new SparseIntArray();
+ @GuardedBy("mUidRulesFirstLock") final SparseIntArray mUidPolicy = new SparseIntArray();
/** Currently derived rules for each UID. */
- final SparseIntArray mUidRules = new SparseIntArray();
+ @GuardedBy("mUidRulesFirstLock") final SparseIntArray mUidRules = new SparseIntArray();
+ @GuardedBy("mUidRulesFirstLock")
final SparseIntArray mUidFirewallStandbyRules = new SparseIntArray();
+ @GuardedBy("mUidRulesFirstLock")
final SparseIntArray mUidFirewallDozableRules = new SparseIntArray();
+ @GuardedBy("mUidRulesFirstLock")
final SparseIntArray mUidFirewallPowerSaveRules = new SparseIntArray();
/** Set of states for the child firewall chains. True if the chain is active. */
+ @GuardedBy("mUidRulesFirstLock")
final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
/**
@@ -314,6 +345,7 @@
* in power save mode, except device idle (doze) still applies.
* TODO: An int array might be sufficient
*/
+ @GuardedBy("mUidRulesFirstLock")
private final SparseBooleanArray mPowerSaveWhitelistExceptIdleAppIds = new SparseBooleanArray();
/**
@@ -321,18 +353,22 @@
* in power save mode.
* TODO: An int array might be sufficient
*/
+ @GuardedBy("mUidRulesFirstLock")
private final SparseBooleanArray mPowerSaveWhitelistAppIds = new SparseBooleanArray();
+ @GuardedBy("mUidRulesFirstLock")
private final SparseBooleanArray mPowerSaveTempWhitelistAppIds = new SparseBooleanArray();
/**
* UIDs that have been white-listed to avoid restricted background.
*/
+ @GuardedBy("mUidRulesFirstLock")
private final SparseBooleanArray mRestrictBackgroundWhitelistUids = new SparseBooleanArray();
/**
* UIDs that have been initially white-listed by system to avoid restricted background.
*/
+ @GuardedBy("mUidRulesFirstLock")
private final SparseBooleanArray mDefaultRestrictBackgroundWhitelistUids =
new SparseBooleanArray();
@@ -340,18 +376,23 @@
* UIDs that have been initially white-listed by system to avoid restricted background,
* but later revoked by user.
*/
+ @GuardedBy("mUidRulesFirstLock")
private final SparseBooleanArray mRestrictBackgroundWhitelistRevokedUids =
new SparseBooleanArray();
/** Set of ifaces that are metered. */
+ @GuardedBy("mNetworkPoliciesSecondLock")
private ArraySet<String> mMeteredIfaces = new ArraySet<>();
/** Set of over-limit templates that have been notified. */
+ @GuardedBy("mNetworkPoliciesSecondLock")
private final ArraySet<NetworkTemplate> mOverLimitNotified = new ArraySet<>();
/** Set of currently active {@link Notification} tags. */
+ @GuardedBy("mNetworkPoliciesSecondLock")
private final ArraySet<String> mActiveNotifs = new ArraySet<String>();
/** Foreground at UID granularity. */
+ @GuardedBy("mUidRulesFirstLock")
final SparseIntArray mUidState = new SparseIntArray();
/** Higher priority listener before general event dispatch */
@@ -362,6 +403,7 @@
final Handler mHandler;
+ @GuardedBy("allLocks")
private final AtomicFile mPolicyFile;
private final AppOpsManager mAppOps;
@@ -426,7 +468,7 @@
mNotifManager = checkNotNull(notifManager, "missing INotificationManager");
}
- void updatePowerSaveWhitelistLocked() {
+ void updatePowerSaveWhitelistUL() {
try {
int[] whitelist = mDeviceIdleController.getAppIdWhitelistExceptIdle();
mPowerSaveWhitelistExceptIdleAppIds.clear();
@@ -452,19 +494,19 @@
*
* @return whether any uid has been added to {@link #mRestrictBackgroundWhitelistUids}.
*/
- boolean addDefaultRestrictBackgroundWhitelistUidsLocked() {
+ boolean addDefaultRestrictBackgroundWhitelistUidsUL() {
final List<UserInfo> users = mUserManager.getUsers();
final int numberUsers = users.size();
boolean changed = false;
for (int i = 0; i < numberUsers; i++) {
final UserInfo user = users.get(i);
- changed = addDefaultRestrictBackgroundWhitelistUidsLocked(user.id) || changed;
+ changed = addDefaultRestrictBackgroundWhitelistUidsUL(user.id) || changed;
}
return changed;
}
- private boolean addDefaultRestrictBackgroundWhitelistUidsLocked(int userId) {
+ private boolean addDefaultRestrictBackgroundWhitelistUidsUL(int userId) {
final SystemConfig sysConfig = SystemConfig.getInstance();
final PackageManager pm = mContext.getPackageManager();
final ArraySet<String> allowDataUsage = sysConfig.getAllowInDataUsageSave();
@@ -502,7 +544,7 @@
return changed;
}
- void updatePowerSaveTempWhitelistLocked() {
+ void updatePowerSaveTempWhitelistUL() {
try {
// Clear the states of the current whitelist
final int N = mPowerSaveTempWhitelistAppIds.size();
@@ -523,7 +565,7 @@
/**
* Remove unnecessary entries in the temp whitelist
*/
- void purgePowerSaveTempWhitelistLocked() {
+ void purgePowerSaveTempWhitelistUL() {
final int N = mPowerSaveTempWhitelistAppIds.size();
for (int i = N - 1; i >= 0; i--) {
if (mPowerSaveTempWhitelistAppIds.valueAt(i) == false) {
@@ -542,36 +584,38 @@
mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
- synchronized (mRulesLock) {
- updatePowerSaveWhitelistLocked();
- mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
- mPowerManagerInternal.registerLowPowerModeObserver(
- new PowerManagerInternal.LowPowerModeListener() {
- @Override
- public void onLowPowerModeChanged(boolean enabled) {
- if (LOGD) Slog.d(TAG, "onLowPowerModeChanged(" + enabled + ")");
- synchronized (mRulesLock) {
- if (mRestrictPower != enabled) {
- mRestrictPower = enabled;
- updateRulesForRestrictPowerLocked();
- updateRulesForGlobalChangeLocked(true);
+ synchronized (mUidRulesFirstLock) {
+ synchronized (mNetworkPoliciesSecondLock) {
+ updatePowerSaveWhitelistUL();
+ mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
+ mPowerManagerInternal.registerLowPowerModeObserver(
+ new PowerManagerInternal.LowPowerModeListener() {
+ @Override
+ public void onLowPowerModeChanged(boolean enabled) {
+ if (LOGD) Slog.d(TAG, "onLowPowerModeChanged(" + enabled + ")");
+ synchronized (mUidRulesFirstLock) {
+ if (mRestrictPower != enabled) {
+ mRestrictPower = enabled;
+ updateRulesForRestrictPowerUL();
+ }
}
}
+ });
+ mRestrictPower = mPowerManagerInternal.getLowPowerModeEnabled();
+
+ mSystemReady = true;
+
+ // read policy from disk
+ readPolicyAL();
+
+ if (addDefaultRestrictBackgroundWhitelistUidsUL()) {
+ writePolicyAL();
}
- });
- mRestrictPower = mPowerManagerInternal.getLowPowerModeEnabled();
- mSystemReady = true;
-
- // read policy from disk
- readPolicyLocked();
-
- if (addDefaultRestrictBackgroundWhitelistUidsLocked()) {
- writePolicyLocked();
+ setRestrictBackgroundUL(mRestrictBackground);
+ updateRulesForGlobalChangeAL(false);
+ updateNotificationsNL();
}
-
- updateRulesForGlobalChangeLocked(false);
- updateNotificationsLocked();
}
updateScreenOn();
@@ -650,14 +694,14 @@
final private IUidObserver mUidObserver = new IUidObserver.Stub() {
@Override public void onUidStateChanged(int uid, int procState) throws RemoteException {
- synchronized (mRulesLock) {
- updateUidStateLocked(uid, procState);
+ synchronized (mUidRulesFirstLock) {
+ updateUidStateUL(uid, procState);
}
}
@Override public void onUidGone(int uid) throws RemoteException {
- synchronized (mRulesLock) {
- removeUidStateLocked(uid);
+ synchronized (mUidRulesFirstLock) {
+ removeUidStateUL(uid);
}
}
@@ -672,9 +716,9 @@
@Override
public void onReceive(Context context, Intent intent) {
// on background handler thread, and POWER_SAVE_WHITELIST_CHANGED is protected
- synchronized (mRulesLock) {
- updatePowerSaveWhitelistLocked();
- updateRulesForGlobalChangeLocked(false);
+ synchronized (mUidRulesFirstLock) {
+ updatePowerSaveWhitelistUL();
+ updateRulesForRestrictPowerUL();
}
}
};
@@ -682,10 +726,10 @@
final private Runnable mTempPowerSaveChangedCallback = new Runnable() {
@Override
public void run() {
- synchronized (mRulesLock) {
- updatePowerSaveTempWhitelistLocked();
- updateRulesForTempWhitelistChangeLocked();
- purgePowerSaveTempWhitelistLocked();
+ synchronized (mUidRulesFirstLock) {
+ updatePowerSaveTempWhitelistUL();
+ updateRulesForTempWhitelistChangeUL();
+ purgePowerSaveTempWhitelistUL();
}
}
};
@@ -712,8 +756,8 @@
// update rules for UID, since it might be subject to
// global background data policy
if (LOGV) Slog.v(TAG, "ACTION_PACKAGE_ADDED for uid=" + uid);
- synchronized (mRulesLock) {
- updateRestrictionRulesForUidLocked(uid);
+ synchronized (mUidRulesFirstLock) {
+ updateRestrictionRulesForUidUL(uid);
}
}
}
@@ -729,10 +773,12 @@
// remove any policy and update rules to clean up
if (LOGV) Slog.v(TAG, "ACTION_UID_REMOVED for uid=" + uid);
- synchronized (mRulesLock) {
+ synchronized (mUidRulesFirstLock) {
mUidPolicy.delete(uid);
- updateRestrictionRulesForUidLocked(uid);
- writePolicyLocked();
+ updateRestrictionRulesForUidUL(uid);
+ synchronized (mNetworkPoliciesSecondLock) {
+ writePolicyAL();
+ }
}
}
};
@@ -750,16 +796,18 @@
switch (action) {
case ACTION_USER_REMOVED:
case ACTION_USER_ADDED:
- synchronized (mRulesLock) {
+ synchronized (mUidRulesFirstLock) {
// Remove any persistable state for the given user; both cleaning up after a
// USER_REMOVED, and one last sanity check during USER_ADDED
- removeUserStateLocked(userId, true);
+ removeUserStateUL(userId, true);
if (action == ACTION_USER_ADDED) {
// Add apps that are whitelisted by default.
- addDefaultRestrictBackgroundWhitelistUidsLocked(userId);
+ addDefaultRestrictBackgroundWhitelistUidsUL(userId);
}
// Update global restrict for that user
- updateRulesForGlobalChangeLocked(true);
+ synchronized (mNetworkPoliciesSecondLock) {
+ updateRulesForGlobalChangeAL(true);
+ }
}
break;
}
@@ -777,9 +825,9 @@
// READ_NETWORK_USAGE_HISTORY permission above.
maybeRefreshTrustedTime();
- synchronized (mRulesLock) {
- updateNetworkEnabledLocked();
- updateNotificationsLocked();
+ synchronized (mNetworkPoliciesSecondLock) {
+ updateNetworkEnabledNL();
+ updateNotificationsNL();
}
}
};
@@ -828,10 +876,12 @@
EXTRA_WIFI_CONFIGURATION);
if (config.SSID != null) {
final NetworkTemplate template = NetworkTemplate.buildTemplateWifi(config.SSID);
- synchronized (mRulesLock) {
- if (mNetworkPolicy.containsKey(template)) {
- mNetworkPolicy.remove(template);
- writePolicyLocked();
+ synchronized (mUidRulesFirstLock) {
+ synchronized (mNetworkPoliciesSecondLock) {
+ if (mNetworkPolicy.containsKey(template)) {
+ mNetworkPolicy.remove(template);
+ writePolicyAL();
+ }
}
}
}
@@ -857,13 +907,13 @@
final boolean meteredHint = info.getMeteredHint();
final NetworkTemplate template = NetworkTemplate.buildTemplateWifi(info.getSSID());
- synchronized (mRulesLock) {
+ synchronized (mNetworkPoliciesSecondLock) {
NetworkPolicy policy = mNetworkPolicy.get(template);
if (policy == null && meteredHint) {
// policy doesn't exist, and AP is hinting that it's
// metered: create an inferred policy.
policy = newWifiPolicy(template, meteredHint);
- addNetworkPolicyLocked(policy);
+ addNetworkPolicyNL(policy);
} else if (policy != null && policy.inferred) {
// policy exists, and was inferred: update its current
@@ -872,7 +922,7 @@
// since this is inferred for each wifi session, just update
// rules without persisting.
- updateNetworkRulesLocked();
+ updateNetworkRulesNL();
}
}
}
@@ -904,8 +954,8 @@
* Check {@link NetworkPolicy} against current {@link INetworkStatsService}
* to show visible notifications as needed.
*/
- void updateNotificationsLocked() {
- if (LOGV) Slog.v(TAG, "updateNotificationsLocked()");
+ void updateNotificationsNL() {
+ if (LOGV) Slog.v(TAG, "updateNotificationsNL()");
// keep track of previously active notifications
final ArraySet<String> beforeNotifs = new ArraySet<String>(mActiveNotifs);
@@ -931,11 +981,11 @@
enqueueNotification(policy, TYPE_LIMIT_SNOOZED, totalBytes);
} else {
enqueueNotification(policy, TYPE_LIMIT, totalBytes);
- notifyOverLimitLocked(policy.template);
+ notifyOverLimitNL(policy.template);
}
} else {
- notifyUnderLimitLocked(policy.template);
+ notifyUnderLimitNL(policy.template);
if (policy.isOverWarning(totalBytes) && policy.lastWarningSnooze < start) {
enqueueNotification(policy, TYPE_WARNING, totalBytes);
@@ -983,14 +1033,14 @@
* Notify that given {@link NetworkTemplate} is over
* {@link NetworkPolicy#limitBytes}, potentially showing dialog to user.
*/
- private void notifyOverLimitLocked(NetworkTemplate template) {
+ private void notifyOverLimitNL(NetworkTemplate template) {
if (!mOverLimitNotified.contains(template)) {
mContext.startActivity(buildNetworkOverLimitIntent(template));
mOverLimitNotified.add(template);
}
}
- private void notifyUnderLimitLocked(NetworkTemplate template) {
+ private void notifyUnderLimitNL(NetworkTemplate template) {
mOverLimitNotified.remove(template);
}
@@ -1142,12 +1192,12 @@
// permission above.
maybeRefreshTrustedTime();
- synchronized (mRulesLock) {
- ensureActiveMobilePolicyLocked();
- normalizePoliciesLocked();
- updateNetworkEnabledLocked();
- updateNetworkRulesLocked();
- updateNotificationsLocked();
+ synchronized (mNetworkPoliciesSecondLock) {
+ ensureActiveMobilePolicyNL();
+ normalizePoliciesNL();
+ updateNetworkEnabledNL();
+ updateNetworkRulesNL();
+ updateNotificationsNL();
}
}
};
@@ -1156,8 +1206,8 @@
* Proactively control network data connections when they exceed
* {@link NetworkPolicy#limitBytes}.
*/
- void updateNetworkEnabledLocked() {
- if (LOGV) Slog.v(TAG, "updateNetworkEnabledLocked()");
+ void updateNetworkEnabledNL() {
+ if (LOGV) Slog.v(TAG, "updateNetworkEnabledNL()");
// TODO: reset any policy-disabled networks when any policy is removed
// completely, which is currently rare case.
@@ -1198,8 +1248,8 @@
* {@link NetworkPolicy} that need to be enforced. When matches found, set
* remaining quota based on usage cycle and historical stats.
*/
- void updateNetworkRulesLocked() {
- if (LOGV) Slog.v(TAG, "updateNetworkRulesLocked()");
+ void updateNetworkRulesNL() {
+ if (LOGV) Slog.v(TAG, "updateNetworkRulesNL()");
final NetworkState[] states;
try {
@@ -1349,8 +1399,8 @@
* Once any {@link #mNetworkPolicy} are loaded from disk, ensure that we
* have at least a default mobile policy defined.
*/
- private void ensureActiveMobilePolicyLocked() {
- if (LOGV) Slog.v(TAG, "ensureActiveMobilePolicyLocked()");
+ private void ensureActiveMobilePolicyNL() {
+ if (LOGV) Slog.v(TAG, "ensureActiveMobilePolicyNL()");
if (mSuppressDefaultPolicy) return;
final TelephonyManager tele = TelephonyManager.from(mContext);
@@ -1359,11 +1409,11 @@
final int[] subIds = sub.getActiveSubscriptionIdList();
for (int subId : subIds) {
final String subscriberId = tele.getSubscriberId(subId);
- ensureActiveMobilePolicyLocked(subscriberId);
+ ensureActiveMobilePolicyNL(subscriberId);
}
}
- private void ensureActiveMobilePolicyLocked(String subscriberId) {
+ private void ensureActiveMobilePolicyNL(String subscriberId) {
// Poke around to see if we already have a policy
final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true);
@@ -1394,11 +1444,11 @@
final NetworkTemplate template = buildTemplateMobileAll(subscriberId);
final NetworkPolicy policy = new NetworkPolicy(template, cycleDay, cycleTimezone,
warningBytes, LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, true, true);
- addNetworkPolicyLocked(policy);
+ addNetworkPolicyNL(policy);
}
- private void readPolicyLocked() {
- if (LOGV) Slog.v(TAG, "readPolicyLocked()");
+ private void readPolicyAL() {
+ if (LOGV) Slog.v(TAG, "readPolicyAL()");
// clear any existing policy and read from disk
mNetworkPolicy.clear();
@@ -1498,7 +1548,7 @@
final int policy = readIntAttribute(in, ATTR_POLICY);
if (UserHandle.isApp(uid)) {
- setUidPolicyUncheckedLocked(uid, policy, false);
+ setUidPolicyUncheckedUL(uid, policy, false);
} else {
Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
}
@@ -1510,7 +1560,7 @@
// app policy is deprecated so this is only used in pre system user split.
final int uid = UserHandle.getUid(UserHandle.USER_SYSTEM, appId);
if (UserHandle.isApp(uid)) {
- setUidPolicyUncheckedLocked(uid, policy, false);
+ setUidPolicyUncheckedUL(uid, policy, false);
} else {
Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
}
@@ -1533,7 +1583,7 @@
} catch (FileNotFoundException e) {
// missing policy is okay, probably first boot
- upgradeLegacyBackgroundData();
+ upgradeLegacyBackgroundDataUL();
} catch (IOException e) {
Log.wtf(TAG, "problem reading network policy", e);
} catch (XmlPullParserException e) {
@@ -1547,7 +1597,7 @@
* Upgrade legacy background data flags, notifying listeners of one last
* change to always-true.
*/
- private void upgradeLegacyBackgroundData() {
+ private void upgradeLegacyBackgroundDataUL() {
mRestrictBackground = Settings.Secure.getInt(
mContext.getContentResolver(), Settings.Secure.BACKGROUND_DATA, 1) != 1;
@@ -1559,8 +1609,8 @@
}
}
- void writePolicyLocked() {
- if (LOGV) Slog.v(TAG, "writePolicyLocked()");
+ void writePolicyAL() {
+ if (LOGV) Slog.v(TAG, "writePolicyAL()");
FileOutputStream fos = null;
try {
@@ -1657,13 +1707,12 @@
if (!UserHandle.isApp(uid)) {
throw new IllegalArgumentException("cannot apply policy to UID " + uid);
}
-
- synchronized (mRulesLock) {
+ synchronized (mUidRulesFirstLock) {
final long token = Binder.clearCallingIdentity();
try {
final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
if (oldPolicy != policy) {
- setUidPolicyUncheckedLocked(uid, oldPolicy, policy, true);
+ setUidPolicyUncheckedUL(uid, oldPolicy, policy, true);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -1679,11 +1728,11 @@
throw new IllegalArgumentException("cannot apply policy to UID " + uid);
}
- synchronized (mRulesLock) {
+ synchronized (mUidRulesFirstLock) {
final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
policy |= oldPolicy;
if (oldPolicy != policy) {
- setUidPolicyUncheckedLocked(uid, oldPolicy, policy, true);
+ setUidPolicyUncheckedUL(uid, oldPolicy, policy, true);
}
}
}
@@ -1696,17 +1745,17 @@
throw new IllegalArgumentException("cannot apply policy to UID " + uid);
}
- synchronized (mRulesLock) {
+ synchronized (mUidRulesFirstLock) {
final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
policy = oldPolicy & ~policy;
if (oldPolicy != policy) {
- setUidPolicyUncheckedLocked(uid, oldPolicy, policy, true);
+ setUidPolicyUncheckedUL(uid, oldPolicy, policy, true);
}
}
}
- private void setUidPolicyUncheckedLocked(int uid, int oldPolicy, int policy, boolean persist) {
- setUidPolicyUncheckedLocked(uid, policy, persist);
+ private void setUidPolicyUncheckedUL(int uid, int oldPolicy, int policy, boolean persist) {
+ setUidPolicyUncheckedUL(uid, policy, persist);
final boolean isBlacklisted = policy == POLICY_REJECT_METERED_BACKGROUND;
mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_BLACKLIST_CHANGED, uid,
@@ -1721,13 +1770,15 @@
}
}
- private void setUidPolicyUncheckedLocked(int uid, int policy, boolean persist) {
+ private void setUidPolicyUncheckedUL(int uid, int policy, boolean persist) {
mUidPolicy.put(uid, policy);
// uid policy changed, recompute rules and persist policy.
- updateRulesForDataUsageRestrictionsLocked(uid);
+ updateRulesForDataUsageRestrictionsUL(uid);
if (persist) {
- writePolicyLocked();
+ synchronized (mNetworkPoliciesSecondLock) {
+ writePolicyAL();
+ }
}
}
@@ -1735,7 +1786,7 @@
public int getUidPolicy(int uid) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
- synchronized (mRulesLock) {
+ synchronized (mUidRulesFirstLock) {
return mUidPolicy.get(uid, POLICY_NONE);
}
}
@@ -1745,7 +1796,7 @@
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
int[] uids = new int[0];
- synchronized (mRulesLock) {
+ synchronized (mUidRulesFirstLock) {
for (int i = 0; i < mUidPolicy.size(); i++) {
final int uid = mUidPolicy.keyAt(i);
final int uidPolicy = mUidPolicy.valueAt(i);
@@ -1761,9 +1812,9 @@
* Removes any persistable state associated with given {@link UserHandle}, persisting
* if any changes that are made.
*/
- boolean removeUserStateLocked(int userId, boolean writePolicy) {
+ boolean removeUserStateUL(int userId, boolean writePolicy) {
- if (LOGV) Slog.v(TAG, "removeUserStateLocked()");
+ if (LOGV) Slog.v(TAG, "removeUserStateUL()");
boolean changed = false;
// Remove entries from restricted background UID whitelist
@@ -1777,7 +1828,7 @@
if (wlUids.length > 0) {
for (int uid : wlUids) {
- removeRestrictBackgroundWhitelistedUidLocked(uid, false, false);
+ removeRestrictBackgroundWhitelistedUidUL(uid, false, false);
}
changed = true;
}
@@ -1806,11 +1857,11 @@
}
changed = true;
}
-
- updateRulesForGlobalChangeLocked(true);
-
- if (writePolicy && changed) {
- writePolicyLocked();
+ synchronized (mNetworkPoliciesSecondLock) {
+ updateRulesForGlobalChangeAL(true);
+ if (writePolicy && changed) {
+ writePolicyAL();
+ }
}
return changed;
}
@@ -1845,19 +1896,21 @@
final long token = Binder.clearCallingIdentity();
try {
maybeRefreshTrustedTime();
- synchronized (mRulesLock) {
- normalizePoliciesLocked(policies);
- updateNetworkEnabledLocked();
- updateNetworkRulesLocked();
- updateNotificationsLocked();
- writePolicyLocked();
+ synchronized (mUidRulesFirstLock) {
+ synchronized (mNetworkPoliciesSecondLock) {
+ normalizePoliciesNL(policies);
+ updateNetworkEnabledNL();
+ updateNetworkRulesNL();
+ updateNotificationsNL();
+ writePolicyAL();
+ }
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
- void addNetworkPolicyLocked(NetworkPolicy policy) {
+ void addNetworkPolicyNL(NetworkPolicy policy) {
NetworkPolicy[] policies = getNetworkPolicies(mContext.getOpPackageName());
policies = ArrayUtils.appendElement(NetworkPolicy.class, policies, policy);
setNetworkPolicies(policies);
@@ -1879,7 +1932,7 @@
}
}
- synchronized (mRulesLock) {
+ synchronized (mNetworkPoliciesSecondLock) {
final int size = mNetworkPolicy.size();
final NetworkPolicy[] policies = new NetworkPolicy[size];
for (int i = 0; i < size; i++) {
@@ -1889,11 +1942,11 @@
}
}
- private void normalizePoliciesLocked() {
- normalizePoliciesLocked(getNetworkPolicies(mContext.getOpPackageName()));
+ private void normalizePoliciesNL() {
+ normalizePoliciesNL(getNetworkPolicies(mContext.getOpPackageName()));
}
- private void normalizePoliciesLocked(NetworkPolicy[] policies) {
+ private void normalizePoliciesNL(NetworkPolicy[] policies) {
final TelephonyManager tele = TelephonyManager.from(mContext);
final String[] merged = tele.getMergedSubscriberIds();
@@ -1927,29 +1980,31 @@
void performSnooze(NetworkTemplate template, int type) {
maybeRefreshTrustedTime();
final long currentTime = currentTimeMillis();
- synchronized (mRulesLock) {
- // find and snooze local policy that matches
- final NetworkPolicy policy = mNetworkPolicy.get(template);
- if (policy == null) {
- throw new IllegalArgumentException("unable to find policy for " + template);
- }
+ synchronized (mUidRulesFirstLock) {
+ synchronized (mNetworkPoliciesSecondLock) {
+ // find and snooze local policy that matches
+ final NetworkPolicy policy = mNetworkPolicy.get(template);
+ if (policy == null) {
+ throw new IllegalArgumentException("unable to find policy for " + template);
+ }
- switch (type) {
- case TYPE_WARNING:
- policy.lastWarningSnooze = currentTime;
- break;
- case TYPE_LIMIT:
- policy.lastLimitSnooze = currentTime;
- break;
- default:
- throw new IllegalArgumentException("unexpected type");
- }
+ switch (type) {
+ case TYPE_WARNING:
+ policy.lastWarningSnooze = currentTime;
+ break;
+ case TYPE_LIMIT:
+ policy.lastLimitSnooze = currentTime;
+ break;
+ default:
+ throw new IllegalArgumentException("unexpected type");
+ }
- normalizePoliciesLocked();
- updateNetworkEnabledLocked();
- updateNetworkRulesLocked();
- updateNotificationsLocked();
- writePolicyLocked();
+ normalizePoliciesNL();
+ updateNetworkEnabledNL();
+ updateNetworkRulesNL();
+ updateNotificationsNL();
+ writePolicyAL();
+ }
}
}
@@ -1957,7 +2012,7 @@
public void onTetheringChanged(String iface, boolean tethering) {
// No need to enforce permission because setRestrictBackground() will do it.
if (LOGD) Log.d(TAG, "onTetherStateChanged(" + iface + ", " + tethering + ")");
- synchronized (mRulesLock) {
+ synchronized (mUidRulesFirstLock) {
if (mRestrictBackground && tethering) {
Log.d(TAG, "Tethering on (" + iface +"); disable Data Saver");
setRestrictBackground(false);
@@ -1971,13 +2026,13 @@
final long token = Binder.clearCallingIdentity();
try {
maybeRefreshTrustedTime();
- synchronized (mRulesLock) {
+ synchronized (mUidRulesFirstLock) {
if (restrictBackground == mRestrictBackground) {
// Ideally, UI should never allow this scenario...
Slog.w(TAG, "setRestrictBackground: already " + restrictBackground);
return;
}
- setRestrictBackgroundLocked(restrictBackground);
+ setRestrictBackgroundUL(restrictBackground);
}
} finally {
@@ -1988,26 +2043,29 @@
.sendToTarget();
}
- private void setRestrictBackgroundLocked(boolean restrictBackground) {
+ private void setRestrictBackgroundUL(boolean restrictBackground) {
+ Slog.d(TAG, "setRestrictBackgroundUL(): " + restrictBackground);
final boolean oldRestrictBackground = mRestrictBackground;
mRestrictBackground = restrictBackground;
// Must whitelist foreground apps before turning data saver mode on.
// TODO: there is no need to iterate through all apps here, just those in the foreground,
// so it could call AM to get the UIDs of such apps, and iterate through them instead.
- updateRulesForRestrictBackgroundLocked();
+ updateRulesForAllAppsUL(TYPE_RESTRICT_BACKGROUND);
try {
if (!mNetworkManager.setDataSaverModeEnabled(mRestrictBackground)) {
Slog.e(TAG, "Could not change Data Saver Mode on NMS to " + mRestrictBackground);
mRestrictBackground = oldRestrictBackground;
// TODO: if it knew the foreground apps (see TODO above), it could call
- // updateRulesForRestrictBackgroundLocked() again to restore state.
+ // updateRulesForRestrictBackgroundUL() again to restore state.
return;
}
} catch (RemoteException e) {
// ignored; service lives in system_server
}
- updateNotificationsLocked();
- writePolicyLocked();
+ synchronized (mNetworkPoliciesSecondLock) {
+ updateNotificationsNL();
+ writePolicyAL();
+ }
}
@Override
@@ -2015,7 +2073,8 @@
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
final boolean oldStatus;
final boolean needFirewallRules;
- synchronized (mRulesLock) {
+ int changed;
+ synchronized (mUidRulesFirstLock) {
oldStatus = mRestrictBackgroundWhitelistUids.get(uid);
if (oldStatus) {
if (LOGD) Slog.d(TAG, "uid " + uid + " is already whitelisted");
@@ -2032,12 +2091,14 @@
}
if (needFirewallRules) {
// Only update firewall rules if necessary...
- updateRulesForDataUsageRestrictionsLocked(uid);
+ updateRulesForDataUsageRestrictionsUL(uid);
}
// ...but always persists the whitelist request.
- writePolicyLocked();
+ synchronized (mNetworkPoliciesSecondLock) {
+ writePolicyAL();
+ }
+ changed = (mRestrictBackground && !oldStatus && needFirewallRules) ? 1 : 0;
}
- int changed = (mRestrictBackground && !oldStatus && needFirewallRules) ? 1 : 0;
mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, changed,
Boolean.TRUE).sendToTarget();
}
@@ -2046,8 +2107,8 @@
public void removeRestrictBackgroundWhitelistedUid(int uid) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
final boolean changed;
- synchronized (mRulesLock) {
- changed = removeRestrictBackgroundWhitelistedUidLocked(uid, false, true);
+ synchronized (mUidRulesFirstLock) {
+ changed = removeRestrictBackgroundWhitelistedUidUL(uid, false, true);
}
mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, changed ? 1 : 0,
Boolean.FALSE).sendToTarget();
@@ -2057,7 +2118,7 @@
* Removes a uid from the restricted background whitelist, returning whether its current
* {@link ConnectivityManager.RestrictBackgroundStatus} changed.
*/
- private boolean removeRestrictBackgroundWhitelistedUidLocked(int uid, boolean uidDeleted,
+ private boolean removeRestrictBackgroundWhitelistedUidUL(int uid, boolean uidDeleted,
boolean updateNow) {
final boolean oldStatus = mRestrictBackgroundWhitelistUids.get(uid);
if (!oldStatus && !uidDeleted) {
@@ -2077,11 +2138,13 @@
}
if (needFirewallRules) {
// Only update firewall rules if necessary...
- updateRulesForDataUsageRestrictionsLocked(uid, uidDeleted);
+ updateRulesForDataUsageRestrictionsUL(uid, uidDeleted);
}
if (updateNow) {
// ...but always persists the whitelist request.
- writePolicyLocked();
+ synchronized (mNetworkPoliciesSecondLock) {
+ writePolicyAL();
+ }
}
// Status only changes if Data Saver is turned on (otherwise it is DISABLED, even if the
// app was whitelisted before).
@@ -2091,7 +2154,7 @@
@Override
public int[] getRestrictBackgroundWhitelistedUids() {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
- synchronized (mRulesLock) {
+ synchronized (mUidRulesFirstLock) {
final int size = mRestrictBackgroundWhitelistUids.size();
final int[] whitelist = new int[size];
for (int i = 0; i < size; i++) {
@@ -2110,7 +2173,7 @@
mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG);
final int uid = Binder.getCallingUid();
- synchronized (mRulesLock) {
+ synchronized (mUidRulesFirstLock) {
// Must clear identity because getUidPolicy() is restricted to system.
final long token = Binder.clearCallingIdentity();
final int policy;
@@ -2136,7 +2199,7 @@
public boolean getRestrictBackground() {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
- synchronized (mRulesLock) {
+ synchronized (mUidRulesFirstLock) {
return mRestrictBackground;
}
}
@@ -2145,13 +2208,13 @@
public void setDeviceIdleMode(boolean enabled) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
- synchronized (mRulesLock) {
+ synchronized (mUidRulesFirstLock) {
if (mDeviceIdleMode != enabled) {
mDeviceIdleMode = enabled;
if (mSystemReady) {
// Device idle change means we need to rebuild rules for all
// known apps, so do a global refresh.
- updateRulesForGlobalChangeLocked(false);
+ updateRulesForRestrictPowerUL();
}
if (enabled) {
EventLogTags.writeDeviceIdleOnPhase("net");
@@ -2162,7 +2225,7 @@
}
}
- private NetworkPolicy findPolicyForNetworkLocked(NetworkIdentity ident) {
+ private NetworkPolicy findPolicyForNetworkNL(NetworkIdentity ident) {
for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
NetworkPolicy policy = mNetworkPolicy.valueAt(i);
if (policy.template.matches(ident)) {
@@ -2190,8 +2253,8 @@
final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
final NetworkPolicy policy;
- synchronized (mRulesLock) {
- policy = findPolicyForNetworkLocked(ident);
+ synchronized (mNetworkPoliciesSecondLock) {
+ policy = findPolicyForNetworkNL(ident);
}
if (policy == null || !policy.hasCycle()) {
@@ -2229,8 +2292,8 @@
}
final NetworkPolicy policy;
- synchronized (mRulesLock) {
- policy = findPolicyForNetworkLocked(ident);
+ synchronized (mNetworkPoliciesSecondLock) {
+ policy = findPolicyForNetworkNL(ident);
}
if (policy != null) {
@@ -2255,155 +2318,157 @@
argSet.add(arg);
}
- synchronized (mRulesLock) {
- if (argSet.contains("--unsnooze")) {
- for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
- mNetworkPolicy.valueAt(i).clearSnooze();
+ synchronized (mUidRulesFirstLock) {
+ synchronized (mNetworkPoliciesSecondLock) {
+ if (argSet.contains("--unsnooze")) {
+ for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
+ mNetworkPolicy.valueAt(i).clearSnooze();
+ }
+
+ normalizePoliciesNL();
+ updateNetworkEnabledNL();
+ updateNetworkRulesNL();
+ updateNotificationsNL();
+ writePolicyAL();
+
+ fout.println("Cleared snooze timestamps");
+ return;
}
- normalizePoliciesLocked();
- updateNetworkEnabledLocked();
- updateNetworkRulesLocked();
- updateNotificationsLocked();
- writePolicyLocked();
-
- fout.println("Cleared snooze timestamps");
- return;
- }
-
- fout.print("System ready: "); fout.println(mSystemReady);
- fout.print("Restrict background: "); fout.println(mRestrictBackground);
- fout.print("Restrict power: "); fout.println(mRestrictPower);
- fout.print("Device idle: "); fout.println(mDeviceIdleMode);
- fout.println("Network policies:");
- fout.increaseIndent();
- for (int i = 0; i < mNetworkPolicy.size(); i++) {
- fout.println(mNetworkPolicy.valueAt(i).toString());
- }
- fout.decreaseIndent();
-
- fout.print("Metered ifaces: "); fout.println(String.valueOf(mMeteredIfaces));
-
- fout.println("Policy for UIDs:");
- fout.increaseIndent();
- int size = mUidPolicy.size();
- for (int i = 0; i < size; i++) {
- final int uid = mUidPolicy.keyAt(i);
- final int policy = mUidPolicy.valueAt(i);
- fout.print("UID=");
- fout.print(uid);
- fout.print(" policy=");
- fout.print(DebugUtils.flagsToString(NetworkPolicyManager.class, "POLICY_", policy));
- fout.println();
- }
- fout.decreaseIndent();
-
- size = mPowerSaveWhitelistExceptIdleAppIds.size();
- if (size > 0) {
- fout.println("Power save whitelist (except idle) app ids:");
+ fout.print("System ready: "); fout.println(mSystemReady);
+ fout.print("Restrict background: "); fout.println(mRestrictBackground);
+ fout.print("Restrict power: "); fout.println(mRestrictPower);
+ fout.print("Device idle: "); fout.println(mDeviceIdleMode);
+ fout.println("Network policies:");
fout.increaseIndent();
+ for (int i = 0; i < mNetworkPolicy.size(); i++) {
+ fout.println(mNetworkPolicy.valueAt(i).toString());
+ }
+ fout.decreaseIndent();
+
+ fout.print("Metered ifaces: "); fout.println(String.valueOf(mMeteredIfaces));
+
+ fout.println("Policy for UIDs:");
+ fout.increaseIndent();
+ int size = mUidPolicy.size();
for (int i = 0; i < size; i++) {
+ final int uid = mUidPolicy.keyAt(i);
+ final int policy = mUidPolicy.valueAt(i);
fout.print("UID=");
- fout.print(mPowerSaveWhitelistExceptIdleAppIds.keyAt(i));
- fout.print(": ");
- fout.print(mPowerSaveWhitelistExceptIdleAppIds.valueAt(i));
+ fout.print(uid);
+ fout.print(" policy=");
+ fout.print(DebugUtils.flagsToString(NetworkPolicyManager.class, "POLICY_", policy));
+ fout.println();
+ }
+ fout.decreaseIndent();
+
+ size = mPowerSaveWhitelistExceptIdleAppIds.size();
+ if (size > 0) {
+ fout.println("Power save whitelist (except idle) app ids:");
+ fout.increaseIndent();
+ for (int i = 0; i < size; i++) {
+ fout.print("UID=");
+ fout.print(mPowerSaveWhitelistExceptIdleAppIds.keyAt(i));
+ fout.print(": ");
+ fout.print(mPowerSaveWhitelistExceptIdleAppIds.valueAt(i));
+ fout.println();
+ }
+ fout.decreaseIndent();
+ }
+
+ size = mPowerSaveWhitelistAppIds.size();
+ if (size > 0) {
+ fout.println("Power save whitelist app ids:");
+ fout.increaseIndent();
+ for (int i = 0; i < size; i++) {
+ fout.print("UID=");
+ fout.print(mPowerSaveWhitelistAppIds.keyAt(i));
+ fout.print(": ");
+ fout.print(mPowerSaveWhitelistAppIds.valueAt(i));
+ fout.println();
+ }
+ fout.decreaseIndent();
+ }
+
+ size = mRestrictBackgroundWhitelistUids.size();
+ if (size > 0) {
+ fout.println("Restrict background whitelist uids:");
+ fout.increaseIndent();
+ for (int i = 0; i < size; i++) {
+ fout.print("UID=");
+ fout.print(mRestrictBackgroundWhitelistUids.keyAt(i));
+ fout.println();
+ }
+ fout.decreaseIndent();
+ }
+
+ size = mDefaultRestrictBackgroundWhitelistUids.size();
+ if (size > 0) {
+ fout.println("Default restrict background whitelist uids:");
+ fout.increaseIndent();
+ for (int i = 0; i < size; i++) {
+ fout.print("UID=");
+ fout.print(mDefaultRestrictBackgroundWhitelistUids.keyAt(i));
+ fout.println();
+ }
+ fout.decreaseIndent();
+ }
+
+ size = mRestrictBackgroundWhitelistRevokedUids.size();
+ if (size > 0) {
+ fout.println("Default restrict background whitelist uids revoked by users:");
+ fout.increaseIndent();
+ for (int i = 0; i < size; i++) {
+ fout.print("UID=");
+ fout.print(mRestrictBackgroundWhitelistRevokedUids.keyAt(i));
+ fout.println();
+ }
+ fout.decreaseIndent();
+ }
+
+ final SparseBooleanArray knownUids = new SparseBooleanArray();
+ collectKeys(mUidState, knownUids);
+ collectKeys(mUidRules, knownUids);
+
+ fout.println("Status for all known UIDs:");
+ fout.increaseIndent();
+ size = knownUids.size();
+ for (int i = 0; i < size; i++) {
+ final int uid = knownUids.keyAt(i);
+ fout.print("UID=");
+ fout.print(uid);
+
+ final int state = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+ fout.print(" state=");
+ fout.print(state);
+ if (state <= ActivityManager.PROCESS_STATE_TOP) {
+ fout.print(" (fg)");
+ } else {
+ fout.print(state <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+ ? " (fg svc)" : " (bg)");
+ }
+
+ final int uidRules = mUidRules.get(uid, RULE_NONE);
+ fout.print(" rules=");
+ fout.print(uidRulesToString(uidRules));
+ fout.println();
+ }
+ fout.decreaseIndent();
+
+ fout.println("Status for just UIDs with rules:");
+ fout.increaseIndent();
+ size = mUidRules.size();
+ for (int i = 0; i < size; i++) {
+ final int uid = mUidRules.keyAt(i);
+ fout.print("UID=");
+ fout.print(uid);
+ final int uidRules = mUidRules.get(uid, RULE_NONE);
+ fout.print(" rules=");
+ fout.print(uidRulesToString(uidRules));
fout.println();
}
fout.decreaseIndent();
}
-
- size = mPowerSaveWhitelistAppIds.size();
- if (size > 0) {
- fout.println("Power save whitelist app ids:");
- fout.increaseIndent();
- for (int i = 0; i < size; i++) {
- fout.print("UID=");
- fout.print(mPowerSaveWhitelistAppIds.keyAt(i));
- fout.print(": ");
- fout.print(mPowerSaveWhitelistAppIds.valueAt(i));
- fout.println();
- }
- fout.decreaseIndent();
- }
-
- size = mRestrictBackgroundWhitelistUids.size();
- if (size > 0) {
- fout.println("Restrict background whitelist uids:");
- fout.increaseIndent();
- for (int i = 0; i < size; i++) {
- fout.print("UID=");
- fout.print(mRestrictBackgroundWhitelistUids.keyAt(i));
- fout.println();
- }
- fout.decreaseIndent();
- }
-
- size = mDefaultRestrictBackgroundWhitelistUids.size();
- if (size > 0) {
- fout.println("Default restrict background whitelist uids:");
- fout.increaseIndent();
- for (int i = 0; i < size; i++) {
- fout.print("UID=");
- fout.print(mDefaultRestrictBackgroundWhitelistUids.keyAt(i));
- fout.println();
- }
- fout.decreaseIndent();
- }
-
- size = mRestrictBackgroundWhitelistRevokedUids.size();
- if (size > 0) {
- fout.println("Default restrict background whitelist uids revoked by users:");
- fout.increaseIndent();
- for (int i = 0; i < size; i++) {
- fout.print("UID=");
- fout.print(mRestrictBackgroundWhitelistRevokedUids.keyAt(i));
- fout.println();
- }
- fout.decreaseIndent();
- }
-
- final SparseBooleanArray knownUids = new SparseBooleanArray();
- collectKeys(mUidState, knownUids);
- collectKeys(mUidRules, knownUids);
-
- fout.println("Status for all known UIDs:");
- fout.increaseIndent();
- size = knownUids.size();
- for (int i = 0; i < size; i++) {
- final int uid = knownUids.keyAt(i);
- fout.print("UID=");
- fout.print(uid);
-
- final int state = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
- fout.print(" state=");
- fout.print(state);
- if (state <= ActivityManager.PROCESS_STATE_TOP) {
- fout.print(" (fg)");
- } else {
- fout.print(state <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
- ? " (fg svc)" : " (bg)");
- }
-
- final int uidRules = mUidRules.get(uid, RULE_NONE);
- fout.print(" rules=");
- fout.print(uidRulesToString(uidRules));
- fout.println();
- }
- fout.decreaseIndent();
-
- fout.println("Status for just UIDs with rules:");
- fout.increaseIndent();
- size = mUidRules.size();
- for (int i = 0; i < size; i++) {
- final int uid = mUidRules.keyAt(i);
- fout.print("UID=");
- fout.print(uid);
- final int uidRules = mUidRules.get(uid, RULE_NONE);
- fout.print(" rules=");
- fout.print(uidRulesToString(uidRules));
- fout.println();
- }
- fout.decreaseIndent();
}
}
@@ -2418,74 +2483,74 @@
public boolean isUidForeground(int uid) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
- synchronized (mRulesLock) {
- return isUidForegroundLocked(uid);
+ synchronized (mUidRulesFirstLock) {
+ return isUidForegroundUL(uid);
}
}
- private boolean isUidForegroundLocked(int uid) {
- return isUidStateForegroundLocked(
+ private boolean isUidForegroundUL(int uid) {
+ return isUidStateForegroundUL(
mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY));
}
- private boolean isUidForegroundOnRestrictBackgroundLocked(int uid) {
+ private boolean isUidForegroundOnRestrictBackgroundUL(int uid) {
final int procState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
- return isProcStateAllowedWhileOnRestrictBackgroundLocked(procState);
+ return isProcStateAllowedWhileOnRestrictBackground(procState);
}
- private boolean isUidForegroundOnRestrictPowerLocked(int uid) {
+ private boolean isUidForegroundOnRestrictPowerUL(int uid) {
final int procState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
return isProcStateAllowedWhileIdleOrPowerSaveMode(procState);
}
- private boolean isUidStateForegroundLocked(int state) {
+ private boolean isUidStateForegroundUL(int state) {
// only really in foreground when screen is also on
return mScreenOn && state <= ActivityManager.PROCESS_STATE_TOP;
}
/**
* Process state of UID changed; if needed, will trigger
- * {@link #updateRulesForDataUsageRestrictionsLocked(int)} and
- * {@link #updateRulesForPowerRestrictionsLocked(int)}
+ * {@link #updateRulesForDataUsageRestrictionsUL(int)} and
+ * {@link #updateRulesForPowerRestrictionsUL(int)}
*/
- private void updateUidStateLocked(int uid, int uidState) {
+ private void updateUidStateUL(int uid, int uidState) {
final int oldUidState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
if (oldUidState != uidState) {
// state changed, push updated rules
mUidState.put(uid, uidState);
- updateRestrictBackgroundRulesOnUidStatusChangedLocked(uid, oldUidState, uidState);
+ updateRestrictBackgroundRulesOnUidStatusChangedUL(uid, oldUidState, uidState);
if (isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState)
!= isProcStateAllowedWhileIdleOrPowerSaveMode(uidState) ) {
if (isUidIdle(uid)) {
- updateRuleForAppIdleLocked(uid);
+ updateRuleForAppIdleUL(uid);
}
if (mDeviceIdleMode) {
- updateRuleForDeviceIdleLocked(uid);
+ updateRuleForDeviceIdleUL(uid);
}
if (mRestrictPower) {
- updateRuleForRestrictPowerLocked(uid);
+ updateRuleForRestrictPowerUL(uid);
}
- updateRulesForPowerRestrictionsLocked(uid);
+ updateRulesForPowerRestrictionsUL(uid);
}
- updateNetworkStats(uid, isUidStateForegroundLocked(uidState));
+ updateNetworkStats(uid, isUidStateForegroundUL(uidState));
}
}
- private void removeUidStateLocked(int uid) {
+ private void removeUidStateUL(int uid) {
final int index = mUidState.indexOfKey(uid);
if (index >= 0) {
final int oldUidState = mUidState.valueAt(index);
mUidState.removeAt(index);
if (oldUidState != ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
- updateRestrictBackgroundRulesOnUidStatusChangedLocked(uid, oldUidState,
+ updateRestrictBackgroundRulesOnUidStatusChangedUL(uid, oldUidState,
ActivityManager.PROCESS_STATE_CACHED_EMPTY);
if (mDeviceIdleMode) {
- updateRuleForDeviceIdleLocked(uid);
+ updateRuleForDeviceIdleUL(uid);
}
if (mRestrictPower) {
- updateRuleForRestrictPowerLocked(uid);
+ updateRuleForRestrictPowerUL(uid);
}
- updateRulesForPowerRestrictionsLocked(uid);
+ updateRulesForPowerRestrictionsUL(uid);
updateNetworkStats(uid, false);
}
}
@@ -2500,38 +2565,38 @@
}
}
- private void updateRestrictBackgroundRulesOnUidStatusChangedLocked(int uid, int oldUidState,
+ private void updateRestrictBackgroundRulesOnUidStatusChangedUL(int uid, int oldUidState,
int newUidState) {
final boolean oldForeground =
- isProcStateAllowedWhileOnRestrictBackgroundLocked(oldUidState);
+ isProcStateAllowedWhileOnRestrictBackground(oldUidState);
final boolean newForeground =
- isProcStateAllowedWhileOnRestrictBackgroundLocked(newUidState);
+ isProcStateAllowedWhileOnRestrictBackground(newUidState);
if (oldForeground != newForeground) {
- updateRulesForDataUsageRestrictionsLocked(uid);
+ updateRulesForDataUsageRestrictionsUL(uid);
}
}
private void updateScreenOn() {
- synchronized (mRulesLock) {
+ synchronized (mUidRulesFirstLock) {
try {
mScreenOn = mPowerManager.isInteractive();
} catch (RemoteException e) {
// ignored; service lives in system_server
}
- updateRulesForScreenLocked();
+ updateRulesForScreenUL();
}
}
/**
* Update rules that might be changed by {@link #mScreenOn} value.
*/
- private void updateRulesForScreenLocked() {
+ private void updateRulesForScreenUL() {
// only update rules for anyone with foreground activities
final int size = mUidState.size();
for (int i = 0; i < size; i++) {
if (mUidState.valueAt(i) <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
final int uid = mUidState.keyAt(i);
- updateRestrictionRulesForUidLocked(uid);
+ updateRestrictionRulesForUidUL(uid);
}
}
}
@@ -2540,31 +2605,31 @@
return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
}
- static boolean isProcStateAllowedWhileOnRestrictBackgroundLocked(int procState) {
+ static boolean isProcStateAllowedWhileOnRestrictBackground(int procState) {
return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
}
- void updateRulesForRestrictPowerLocked() {
- updateRulesForWhitelistedPowerSaveLocked(mRestrictPower, FIREWALL_CHAIN_POWERSAVE,
+ void updateRulesForPowerSaveUL() {
+ updateRulesForWhitelistedPowerSaveUL(mRestrictPower, FIREWALL_CHAIN_POWERSAVE,
mUidFirewallPowerSaveRules);
}
- void updateRuleForRestrictPowerLocked(int uid) {
- updateRulesForWhitelistedPowerSaveLocked(uid, mRestrictPower, FIREWALL_CHAIN_POWERSAVE);
+ void updateRuleForRestrictPowerUL(int uid) {
+ updateRulesForWhitelistedPowerSaveUL(uid, mRestrictPower, FIREWALL_CHAIN_POWERSAVE);
}
- void updateRulesForDeviceIdleLocked() {
- updateRulesForWhitelistedPowerSaveLocked(mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE,
+ void updateRulesForDeviceIdleUL() {
+ updateRulesForWhitelistedPowerSaveUL(mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE,
mUidFirewallDozableRules);
}
- void updateRuleForDeviceIdleLocked(int uid) {
- updateRulesForWhitelistedPowerSaveLocked(uid, mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE);
+ void updateRuleForDeviceIdleUL(int uid) {
+ updateRulesForWhitelistedPowerSaveUL(uid, mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE);
}
// NOTE: since both fw_dozable and fw_powersave uses the same map
// (mPowerSaveTempWhitelistAppIds) for whitelisting, we can reuse their logic in this method.
- private void updateRulesForWhitelistedPowerSaveLocked(boolean enabled, int chain,
+ private void updateRulesForWhitelistedPowerSaveUL(boolean enabled, int chain,
SparseIntArray rules) {
if (enabled) {
// Sync the whitelists before enabling the chain. We don't care about the rules if
@@ -2595,23 +2660,19 @@
setUidFirewallRules(chain, uidRules);
}
- enableFirewallChainLocked(chain, enabled);
+ enableFirewallChainUL(chain, enabled);
}
- private void updateRulesForNonMeteredNetworksLocked() {
-
- }
-
- private boolean isWhitelistedBatterySaverLocked(int uid) {
+ private boolean isWhitelistedBatterySaverUL(int uid) {
final int appId = UserHandle.getAppId(uid);
return mPowerSaveTempWhitelistAppIds.get(appId) || mPowerSaveWhitelistAppIds.get(appId);
}
// NOTE: since both fw_dozable and fw_powersave uses the same map
// (mPowerSaveTempWhitelistAppIds) for whitelisting, we can reuse their logic in this method.
- private void updateRulesForWhitelistedPowerSaveLocked(int uid, boolean enabled, int chain) {
+ private void updateRulesForWhitelistedPowerSaveUL(int uid, boolean enabled, int chain) {
if (enabled) {
- if (isWhitelistedBatterySaverLocked(uid)
+ if (isWhitelistedBatterySaverUL(uid)
|| isProcStateAllowedWhileIdleOrPowerSaveMode(mUidState.get(uid))) {
setUidFirewallRule(chain, uid, FIREWALL_RULE_ALLOW);
} else {
@@ -2620,7 +2681,7 @@
}
}
- void updateRulesForAppIdleLocked() {
+ void updateRulesForAppIdleUL() {
final SparseIntArray uidRules = mUidFirewallStandbyRules;
uidRules.clear();
@@ -2644,50 +2705,69 @@
setUidFirewallRules(FIREWALL_CHAIN_STANDBY, uidRules);
}
- void updateRuleForAppIdleLocked(int uid) {
+ void updateRuleForAppIdleUL(int uid) {
if (!isUidValidForBlacklistRules(uid)) return;
int appId = UserHandle.getAppId(uid);
if (!mPowerSaveTempWhitelistAppIds.get(appId) && isUidIdle(uid)
- && !isUidForegroundOnRestrictPowerLocked(uid)) {
+ && !isUidForegroundOnRestrictPowerUL(uid)) {
setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DENY);
} else {
setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DEFAULT);
}
}
- void updateRulesForAppIdleParoleLocked() {
+ void updateRulesForAppIdleParoleUL() {
boolean enableChain = !mUsageStats.isAppIdleParoleOn();
- enableFirewallChainLocked(FIREWALL_CHAIN_STANDBY, enableChain);
+ enableFirewallChainUL(FIREWALL_CHAIN_STANDBY, enableChain);
}
/**
* Update rules that might be changed by {@link #mRestrictBackground},
* {@link #mRestrictPower}, or {@link #mDeviceIdleMode} value.
*/
- private void updateRulesForGlobalChangeLocked(boolean restrictedNetworksChanged) {
+ private void updateRulesForGlobalChangeAL(boolean restrictedNetworksChanged) {
long start;
if (LOGD) start = System.currentTimeMillis();
- updateRulesForDeviceIdleLocked();
- updateRulesForAppIdleLocked();
- updateRulesForRestrictPowerLocked();
- updateRulesForRestrictBackgroundLocked();
- setRestrictBackgroundLocked(mRestrictBackground);
+ updateRulesForRestrictPowerUL();
+ updateRulesForRestrictBackgroundUL();
// If the set of restricted networks may have changed, re-evaluate those.
if (restrictedNetworksChanged) {
- normalizePoliciesLocked();
- updateNetworkRulesLocked();
+ normalizePoliciesNL();
+ updateNetworkRulesNL();
}
if (LOGD) {
final long delta = System.currentTimeMillis() - start;
- Slog.d(TAG, "updateRulesForGlobalChangeLocked(" + restrictedNetworksChanged + ") took "
+ Slog.d(TAG, "updateRulesForGlobalChangeAL(" + restrictedNetworksChanged + ") took "
+ delta + "ms");
}
}
- private void updateRulesForRestrictBackgroundLocked() {
+ private void updateRulesForRestrictPowerUL() {
+ updateRulesForDeviceIdleUL();
+ updateRulesForAppIdleUL();
+ updateRulesForPowerSaveUL();
+ updateRulesForAllAppsUL(TYPE_RESTRICT_POWER);
+ }
+
+ private void updateRulesForRestrictBackgroundUL() {
+ updateRulesForAllAppsUL(TYPE_RESTRICT_BACKGROUND);
+ }
+
+ private static final int TYPE_RESTRICT_BACKGROUND = 1;
+ private static final int TYPE_RESTRICT_POWER = 2;
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = false, value = {
+ TYPE_RESTRICT_BACKGROUND,
+ TYPE_RESTRICT_POWER,
+ })
+ public @interface RestrictType {
+ }
+
+ // TODO: refactor / consolidate all those updateXyz methods, there are way too many of them...
+ private void updateRulesForAllAppsUL(@RestrictType int type) {
final PackageManager pm = mContext.getPackageManager();
// update rules for all installed applications
@@ -2704,25 +2784,34 @@
for (int j = 0; j < appsSize; j++) {
final ApplicationInfo app = apps.get(j);
final int uid = UserHandle.getUid(user.id, app.uid);
- updateRulesForDataUsageRestrictionsLocked(uid);
- updateRulesForPowerRestrictionsLocked(uid);
+ switch (type) {
+ case TYPE_RESTRICT_BACKGROUND:
+ updateRulesForDataUsageRestrictionsUL(uid);
+ break;
+ case TYPE_RESTRICT_POWER:
+ updateRulesForPowerRestrictionsUL(uid);
+ break;
+ default:
+ Slog.w(TAG, "Invalid type for updateRulesForAllApps: " + type);
+ }
}
}
}
- private void updateRulesForTempWhitelistChangeLocked() {
+ private void updateRulesForTempWhitelistChangeUL() {
final List<UserInfo> users = mUserManager.getUsers();
for (int i = 0; i < users.size(); i++) {
final UserInfo user = users.get(i);
for (int j = mPowerSaveTempWhitelistAppIds.size() - 1; j >= 0; j--) {
int appId = mPowerSaveTempWhitelistAppIds.keyAt(j);
int uid = UserHandle.getUid(user.id, appId);
+ updateRulesForRestrictPowerUL();
// Update external firewall rules.
- updateRuleForAppIdleLocked(uid);
- updateRuleForDeviceIdleLocked(uid);
- updateRuleForRestrictPowerLocked(uid);
+ updateRuleForAppIdleUL(uid);
+ updateRuleForDeviceIdleUL(uid);
+ updateRuleForRestrictPowerUL(uid);
// Update internal rules.
- updateRulesForPowerRestrictionsLocked(uid);
+ updateRulesForPowerRestrictionsUL(uid);
}
}
}
@@ -2786,17 +2875,17 @@
*
* <p>This method changes both the external firewall rules and the internal state.
*/
- private void updateRestrictionRulesForUidLocked(int uid) {
+ private void updateRestrictionRulesForUidUL(int uid) {
// Methods below only changes the firewall rules for the power-related modes.
- updateRuleForDeviceIdleLocked(uid);
- updateRuleForAppIdleLocked(uid);
- updateRuleForRestrictPowerLocked(uid);
+ updateRuleForDeviceIdleUL(uid);
+ updateRuleForAppIdleUL(uid);
+ updateRuleForRestrictPowerUL(uid);
// Update internal state for power-related modes.
- updateRulesForPowerRestrictionsLocked(uid);
+ updateRulesForPowerRestrictionsUL(uid);
// Update firewall and internal rules for Data Saver Mode.
- updateRulesForDataUsageRestrictionsLocked(uid);
+ updateRulesForDataUsageRestrictionsUL(uid);
}
/**
@@ -2818,7 +2907,7 @@
* {@link #setUidPolicy(int, int)} and {@link #addRestrictBackgroundWhitelistedUid(int)} /
* {@link #removeRestrictBackgroundWhitelistedUid(int)} methods (for blacklist and whitelist
* respectively): these methods set the proper internal state (blacklist / whitelist), then call
- * this ({@link #updateRulesForDataUsageRestrictionsLocked(int)}) to propagate the rules to
+ * this ({@link #updateRulesForDataUsageRestrictionsUL(int)}) to propagate the rules to
* {@link INetworkManagementService}, but this method should also be called in events (like
* Data Saver Mode flips or UID state changes) that might affect the foreground app, since the
* following rules should also be applied:
@@ -2838,15 +2927,15 @@
* <p>The {@link #mUidRules} map is used to define the transtion of states of an UID.
*
*/
- private void updateRulesForDataUsageRestrictionsLocked(int uid) {
- updateRulesForDataUsageRestrictionsLocked(uid, false);
+ private void updateRulesForDataUsageRestrictionsUL(int uid) {
+ updateRulesForDataUsageRestrictionsUL(uid, false);
}
/**
- * Overloaded version of {@link #updateRulesForDataUsageRestrictionsLocked(int)} called when an
+ * Overloaded version of {@link #updateRulesForDataUsageRestrictionsUL(int)} called when an
* app is removed - it ignores the UID validity check.
*/
- private void updateRulesForDataUsageRestrictionsLocked(int uid, boolean uidDeleted) {
+ private void updateRulesForDataUsageRestrictionsUL(int uid, boolean uidDeleted) {
if (!uidDeleted && !isUidValidForWhitelistRules(uid)) {
if (LOGD) Slog.d(TAG, "no need to update restrict data rules for uid " + uid);
return;
@@ -2854,7 +2943,7 @@
final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
final int oldUidRules = mUidRules.get(uid, RULE_NONE);
- final boolean isForeground = isUidForegroundOnRestrictBackgroundLocked(uid);
+ final boolean isForeground = isUidForegroundOnRestrictBackgroundUL(uid);
final boolean isBlacklisted = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
final boolean isWhitelisted = mRestrictBackgroundWhitelistUids.get(uid);
@@ -2878,7 +2967,7 @@
final int newUidRules = newRule | (oldUidRules & MASK_ALL_NETWORKS);
if (LOGV) {
- Log.v(TAG, "updateRuleForRestrictBackgroundLocked(" + uid + ")"
+ Log.v(TAG, "updateRuleForRestrictBackgroundUL(" + uid + ")"
+ ": isForeground=" +isForeground
+ ", isBlacklisted=" + isBlacklisted
+ ", isWhitelisted=" + isWhitelisted
@@ -2971,7 +3060,7 @@
* <p>
* <strong>NOTE: </strong>This method does not update the firewall rules on {@code netd}.
*/
- private void updateRulesForPowerRestrictionsLocked(int uid) {
+ private void updateRulesForPowerRestrictionsUL(int uid) {
if (!isUidValidForBlacklistRules(uid)) {
if (LOGD) Slog.d(TAG, "no need to update restrict power rules for uid " + uid);
return;
@@ -2981,9 +3070,9 @@
final boolean restrictMode = isIdle || mRestrictPower || mDeviceIdleMode;
final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
final int oldUidRules = mUidRules.get(uid, RULE_NONE);
- final boolean isForeground = isUidForegroundOnRestrictPowerLocked(uid);
+ final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid);
- final boolean isWhitelisted = isWhitelistedBatterySaverLocked(uid);
+ final boolean isWhitelisted = isWhitelistedBatterySaverUL(uid);
final int oldRule = oldUidRules & MASK_ALL_NETWORKS;
int newRule = RULE_NONE;
@@ -3002,7 +3091,7 @@
final int newUidRules = (oldUidRules & MASK_METERED_NETWORKS) | newRule;
if (LOGV) {
- Log.v(TAG, "updateRulesForNonMeteredNetworksLocked(" + uid + ")"
+ Log.v(TAG, "updateRulesForNonMeteredNetworksUL(" + uid + ")"
+ ", isIdle: " + isIdle
+ ", mRestrictPower: " + mRestrictPower
+ ", mDeviceIdleMode: " + mDeviceIdleMode
@@ -3047,9 +3136,9 @@
final int uid = mContext.getPackageManager().getPackageUidAsUser(packageName,
PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
if (LOGV) Log.v(TAG, "onAppIdleStateChanged(): uid=" + uid + ", idle=" + idle);
- synchronized (mRulesLock) {
- updateRuleForAppIdleLocked(uid);
- updateRulesForPowerRestrictionsLocked(uid);
+ synchronized (mUidRulesFirstLock) {
+ updateRuleForAppIdleUL(uid);
+ updateRulesForPowerRestrictionsUL(uid);
}
} catch (NameNotFoundException nnfe) {
}
@@ -3057,8 +3146,8 @@
@Override
public void onParoleStateChanged(boolean isParoleOn) {
- synchronized (mRulesLock) {
- updateRulesForAppIdleParoleLocked();
+ synchronized (mUidRulesFirstLock) {
+ updateRulesForAppIdleParoleUL();
}
}
}
@@ -3143,7 +3232,7 @@
final String iface = (String) msg.obj;
maybeRefreshTrustedTime();
- synchronized (mRulesLock) {
+ synchronized (mNetworkPoliciesSecondLock) {
if (mMeteredIfaces.contains(iface)) {
try {
// force stats update to make sure we have
@@ -3153,8 +3242,8 @@
// ignored; service lives in system_server
}
- updateNetworkEnabledLocked();
- updateNotificationsLocked();
+ updateNetworkEnabledNL();
+ updateNotificationsNL();
}
}
return true;
@@ -3354,7 +3443,7 @@
/**
* Add or remove a uid to the firewall blacklist for all network ifaces.
*/
- private void enableFirewallChainLocked(int chain, boolean enable) {
+ private void enableFirewallChainUL(int chain, boolean enable) {
if (mFirewallChainStates.indexOfKey(chain) >= 0 &&
mFirewallChainStates.get(chain) == enable) {
// All is the same, nothing to do.
@@ -3483,9 +3572,9 @@
@Override
public void onPackageRemoved(String packageName, int uid) {
if (LOGV) Slog.v(TAG, "onPackageRemoved: " + packageName + " ->" + uid);
- synchronized (mRulesLock) {
- removeRestrictBackgroundWhitelistedUidLocked(uid, true, true);
- updateRestrictionRulesForUidLocked(uid);
+ synchronized (mUidRulesFirstLock) {
+ removeRestrictBackgroundWhitelistedUidUL(uid, true, true);
+ updateRestrictionRulesForUidUL(uid);
}
}
}
@@ -3494,11 +3583,13 @@
@Override
public void resetUserState(int userId) {
- synchronized (mRulesLock) {
- boolean changed = removeUserStateLocked(userId, false);
- changed = addDefaultRestrictBackgroundWhitelistUidsLocked(userId) || changed;
+ synchronized (mUidRulesFirstLock) {
+ boolean changed = removeUserStateUL(userId, false);
+ changed = addDefaultRestrictBackgroundWhitelistUidsUL(userId) || changed;
if (changed) {
- writePolicyLocked();
+ synchronized (mNetworkPoliciesSecondLock) {
+ writePolicyAL();
+ }
}
}
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsObservers.java b/services/core/java/com/android/server/net/NetworkStatsObservers.java
index ea36170..3360584 100644
--- a/services/core/java/com/android/server/net/NetworkStatsObservers.java
+++ b/services/core/java/com/android/server/net/NetworkStatsObservers.java
@@ -355,9 +355,10 @@
@Override
protected void recordSample(StatsContext statsContext) {
// Recorder does not need to be locked in this context since only the handler
- // thread will update it
+ // thread will update it. We pass a null VPN array because usage is aggregated by uid
+ // for this snapshot, so VPN traffic can't be reattributed to responsible apps.
mRecorder.recordSnapshotLocked(statsContext.mXtSnapshot, statsContext.mActiveIfaces,
- statsContext.mVpnArray, statsContext.mCurrentTime);
+ null /* vpnArray */, statsContext.mCurrentTime);
}
/**
@@ -396,7 +397,8 @@
@Override
protected void recordSample(StatsContext statsContext) {
// Recorder does not need to be locked in this context since only the handler
- // thread will update it
+ // thread will update it. We pass the VPN info so VPN traffic is reattributed to
+ // responsible apps.
mRecorder.recordSnapshotLocked(statsContext.mUidSnapshot, statsContext.mActiveUidIfaces,
statsContext.mVpnArray, statsContext.mCurrentTime);
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
index 04dc917..090a076 100644
--- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
@@ -22,6 +22,7 @@
import static android.text.format.DateUtils.YEAR_IN_MILLIS;
import static com.android.internal.util.Preconditions.checkNotNull;
+import android.annotation.Nullable;
import android.net.NetworkStats;
import android.net.NetworkStats.NonMonotonicObserver;
import android.net.NetworkStatsHistory;
@@ -199,9 +200,14 @@
* Record any delta that occurred since last {@link NetworkStats} snapshot,
* using the given {@link Map} to identify network interfaces. First
* snapshot is considered bootstrap, and is not counted as delta.
+ *
+ * @param vpnArray Optional info about the currently active VPN, if any. This is used to
+ * redistribute traffic from the VPN app to the underlying responsible apps.
+ * This should always be set to null if the provided snapshot is aggregated
+ * across all UIDs (e.g. contains UID_ALL buckets), regardless of VPN state.
*/
public void recordSnapshotLocked(NetworkStats snapshot,
- Map<String, NetworkIdentitySet> ifaceIdent, VpnInfo[] vpnArray,
+ Map<String, NetworkIdentitySet> ifaceIdent, @Nullable VpnInfo[] vpnArray,
long currentTimeMillis) {
final HashSet<String> unknownIfaces = Sets.newHashSet();
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 8610fa1..23c111e 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -1009,9 +1009,16 @@
final NetworkStats xtSnapshot = mNetworkManager.getNetworkStatsSummaryXt();
final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev();
+
+ // For xt/dev, we pass a null VPN array because usage is aggregated by UID, so VPN traffic
+ // can't be reattributed to responsible apps.
+ mDevRecorder.recordSnapshotLocked(
+ devSnapshot, mActiveIfaces, null /* vpnArray */, currentTime);
+ mXtRecorder.recordSnapshotLocked(
+ xtSnapshot, mActiveIfaces, null /* vpnArray */, currentTime);
+
+ // For per-UID stats, pass the VPN info so VPN traffic is reattributed to responsible apps.
VpnInfo[] vpnArray = mConnManager.getAllVpnInfo();
- mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, null, currentTime);
- mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, null, currentTime);
mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime);
mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 0af0c73..73850de 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -67,7 +67,6 @@
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
@@ -2521,6 +2520,8 @@
return;
}
+ mUsageStats.registerEnqueuedByApp(pkg);
+
// Limit the number of notifications that any given package except the android
// package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
if (!isSystemNotification && !isNotificationFromListener) {
@@ -2614,17 +2615,18 @@
private static void setPendingIntentWhitelistDuration(ActivityManagerInternal am, long duration,
Bundle extras) {
for (String key : extras.keySet()) {
- setPendingIntentWhitelistDuration(am, duration, extras.getParcelable(key));
- final Parcelable[] parcelableArray = extras.getParcelableArray(key);
- if (parcelableArray != null) {
- for (Parcelable parcelable: parcelableArray) {
+ final Object value = extras.get(key);
+ if (value instanceof Parcelable) {
+ setPendingIntentWhitelistDuration(am, duration, (Parcelable) value);
+ } else if (value instanceof Parcelable[]) {
+ for (Parcelable parcelable : (Parcelable[]) value) {
setPendingIntentWhitelistDuration(am, duration, parcelable);
}
- }
- final ArrayList<Parcelable> parcelableList = extras.getParcelableArrayList(key);
- if (parcelableList != null) {
- for (Parcelable parcelable: parcelableList) {
- setPendingIntentWhitelistDuration(am, duration, parcelable);
+ } else if (value instanceof List) {
+ for (Object element : (List <?>) value) {
+ if (element instanceof Parcelable) {
+ setPendingIntentWhitelistDuration(am, duration, (Parcelable) element);
+ }
}
}
}
@@ -2802,7 +2804,7 @@
// notification was a summary and its group key changed.
if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
cancelGroupChildrenLocked(old, callingUid, callingPid, null,
- REASON_GROUP_SUMMARY_CANCELED);
+ REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
}
}
@@ -3435,7 +3437,7 @@
cancelNotificationLocked(r, sendDelete, reason);
cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
- REASON_GROUP_SUMMARY_CANCELED);
+ REASON_GROUP_SUMMARY_CANCELED, sendDelete);
updateLightsLocked();
}
}
@@ -3514,7 +3516,7 @@
final int M = canceledNotifications.size();
for (int i = 0; i < M; i++) {
cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
- listenerName, REASON_GROUP_SUMMARY_CANCELED);
+ listenerName, REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
}
}
if (canceledNotifications != null) {
@@ -3558,14 +3560,14 @@
int M = canceledNotifications != null ? canceledNotifications.size() : 0;
for (int i = 0; i < M; i++) {
cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
- listenerName, REASON_GROUP_SUMMARY_CANCELED);
+ listenerName, REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
}
updateLightsLocked();
}
// Warning: The caller is responsible for invoking updateLightsLocked().
private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
- String listenerName, int reason) {
+ String listenerName, int reason, boolean sendDelete) {
Notification n = r.getNotification();
if (!n.isGroupSummary()) {
return;
@@ -3588,7 +3590,7 @@
EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
childSbn.getTag(), userId, 0, 0, reason, listenerName);
mNotificationList.remove(i);
- cancelNotificationLocked(childR, false, reason);
+ cancelNotificationLocked(childR, sendDelete, reason);
}
}
}
@@ -3896,7 +3898,9 @@
@Override
public void onUserSwitched(int user) {
synchronized (mNotificationList) {
- for (ManagedServiceInfo info : mServices) {
+ int i = mServices.size()-1;
+ while (i --> 0) {
+ final ManagedServiceInfo info = mServices.get(i);
unregisterService(info.service, info.userid);
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index 7b573da..34c5283 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -114,6 +114,17 @@
}
/**
+ * Called when a notification is tentatively enqueued by an app, before rate checking.
+ */
+ public synchronized void registerEnqueuedByApp(String packageName) {
+ AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(packageName);
+ for (AggregatedStats stats : aggregatedStatsArray) {
+ stats.numEnqueuedByApp++;
+ }
+ releaseAggregatedStatsLocked(aggregatedStatsArray);
+ }
+
+ /**
* Called when a notification has been posted.
*/
public synchronized void registerPostedByApp(NotificationRecord notification) {
@@ -135,7 +146,8 @@
/**
* Called when a notification has been updated.
*/
- public void registerUpdatedByApp(NotificationRecord notification, NotificationRecord old) {
+ public synchronized void registerUpdatedByApp(NotificationRecord notification,
+ NotificationRecord old) {
notification.stats.updateFrom(old.stats);
AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification);
for (AggregatedStats stats : aggregatedStatsArray) {
@@ -344,6 +356,7 @@
private AggregatedStats mPrevious;
// ---- Updated as the respective events occur.
+ public int numEnqueuedByApp;
public int numPostedByApp;
public int numUpdatedByApp;
public int numRemovedByApp;
@@ -470,6 +483,7 @@
public void emit() {
AggregatedStats previous = getPrevious();
+ maybeCount("note_enqueued", (numEnqueuedByApp - previous.numEnqueuedByApp));
maybeCount("note_post", (numPostedByApp - previous.numPostedByApp));
maybeCount("note_update", (numUpdatedByApp - previous.numUpdatedByApp));
maybeCount("note_remove", (numRemovedByApp - previous.numRemovedByApp));
@@ -501,6 +515,7 @@
quietImportance.maybeCount(previous.quietImportance);
finalImportance.maybeCount(previous.finalImportance);
+ previous.numEnqueuedByApp = numEnqueuedByApp;
previous.numPostedByApp = numPostedByApp;
previous.numUpdatedByApp = numUpdatedByApp;
previous.numRemovedByApp = numRemovedByApp;
@@ -568,6 +583,8 @@
output.append(indentPlusTwo);
output.append("key='").append(key).append("',\n");
output.append(indentPlusTwo);
+ output.append("numEnqueuedByApp=").append(numEnqueuedByApp).append(",\n");
+ output.append(indentPlusTwo);
output.append("numPostedByApp=").append(numPostedByApp).append(",\n");
output.append(indentPlusTwo);
output.append("numUpdatedByApp=").append(numUpdatedByApp).append(",\n");
@@ -631,6 +648,7 @@
JSONObject dump = new JSONObject();
dump.put("key", key);
dump.put("duration", SystemClock.elapsedRealtime() - mCreated);
+ maybePut(dump, "numEnqueuedByApp", numEnqueuedByApp);
maybePut(dump, "numPostedByApp", numPostedByApp);
maybePut(dump, "numUpdatedByApp", numUpdatedByApp);
maybePut(dump, "numRemovedByApp", numRemovedByApp);
diff --git a/services/core/java/com/android/server/notification/RateEstimator.java b/services/core/java/com/android/server/notification/RateEstimator.java
index c17db4a..a2f93dc 100644
--- a/services/core/java/com/android/server/notification/RateEstimator.java
+++ b/services/core/java/com/android/server/notification/RateEstimator.java
@@ -26,9 +26,12 @@
private static final double RATE_ALPHA = 0.8;
private static final double MINIMUM_DT = 0.0005;
private Long mLastEventTime;
- private Float mInterarrivalTime;
+ private double mInterarrivalTime;
- public RateEstimator() {}
+ public RateEstimator() {
+ // assume something generous if we have no information
+ mInterarrivalTime = 1000.0;
+ }
/** Update the estimate to account for an event that just happened. */
public float update(long now) {
@@ -38,7 +41,7 @@
rate = 0f;
} else {
// Calculate the new inter-arrival time based on last event time.
- mInterarrivalTime = (float) getInterarrivalEstimate(now);
+ mInterarrivalTime = getInterarrivalEstimate(now);
rate = (float) (1.0 / mInterarrivalTime);
}
mLastEventTime = now;
@@ -57,10 +60,6 @@
private double getInterarrivalEstimate(long now) {
double dt = ((double) (now - mLastEventTime)) / 1000.0;
dt = Math.max(dt, MINIMUM_DT);
- if (mInterarrivalTime == null) {
- // No last inter-arrival time, return the new value directly.
- return dt;
- }
// a*iat_old + (1-a)*(t_now-t_last)
return (RATE_ALPHA * mInterarrivalTime + (1.0 - RATE_ALPHA) * dt);
}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 43a0b91..46da607 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -380,7 +380,8 @@
"To query by shortcut ID, package name must also be set");
}
- return new ParceledListSlice<>(
+ // TODO(b/29399275): Eclipse compiler requires explicit List<ShortcutInfo> cast below.
+ return new ParceledListSlice<>((List<ShortcutInfo>)
mShortcutServiceInternal.getShortcuts(getCallingUserId(),
callingPackage, changedSince, packageName, shortcutIds,
componentName, flags, user.getIdentifier()));
@@ -775,8 +776,7 @@
/* changedSince= */ 0, packageName, /* shortcutIds=*/ null,
/* component= */ null,
ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY
- | ShortcutQuery.FLAG_GET_PINNED
- | ShortcutQuery.FLAG_GET_DYNAMIC
+ | ShortcutQuery.FLAG_GET_ALL_KINDS
, userId);
try {
listener.onShortcutChanged(user, packageName,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index fe492c7..62cdefa 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -464,7 +464,7 @@
private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay";
- private static int DEFAULT_EPHEMERAL_HASH_PREFIX_MASK = 0xFFFFFFFF;
+ private static int DEFAULT_EPHEMERAL_HASH_PREFIX_MASK = 0xFFFFF000;
private static int DEFAULT_EPHEMERAL_HASH_PREFIX_COUNT = 5;
/** Permission grant: not grant the permission. */
@@ -1219,7 +1219,9 @@
StringBuffer sb = new StringBuffer();
String firstLine = readLine(in, sb);
- if (firstLine.equals(USAGE_FILE_MAGIC_VERSION_1)) {
+ if (firstLine == null) {
+ // Empty file. Do nothing.
+ } else if (USAGE_FILE_MAGIC_VERSION_1.equals(firstLine)) {
readVersion1LP(in, sb);
} else {
readVersion0LP(in, sb, firstLine);
@@ -4998,7 +5000,8 @@
Global.EPHEMERAL_HASH_PREFIX_MASK, DEFAULT_EPHEMERAL_HASH_PREFIX_MASK);
final int ephemeralPrefixCount = Global.getInt(mContext.getContentResolver(),
Global.EPHEMERAL_HASH_PREFIX_COUNT, DEFAULT_EPHEMERAL_HASH_PREFIX_COUNT);
- final EphemeralDigest digest = new EphemeralDigest(intent.getData(), ephemeralPrefixCount);
+ final EphemeralDigest digest = new EphemeralDigest(intent.getData(), ephemeralPrefixMask,
+ ephemeralPrefixCount);
final int[] shaPrefix = digest.getDigestPrefix();
final byte[][] digestBytes = digest.getDigestBytes();
final List<EphemeralResolveInfo> ephemeralResolveInfoList =
@@ -5010,7 +5013,7 @@
}
// Go in reverse order so we match the narrowest scope first.
- for (int i = shaPrefix.length; i >= 0 ; --i) {
+ for (int i = shaPrefix.length - 1; i >= 0 ; --i) {
for (EphemeralResolveInfo ephemeralApplication : ephemeralResolveInfoList) {
if (!Arrays.equals(digestBytes[i], ephemeralApplication.getDigestBytes())) {
continue;
@@ -6760,11 +6763,26 @@
}
}
+ private long getLastModifiedTime(PackageParser.Package pkg, File srcFile) {
+ if (srcFile.isDirectory()) {
+ final File baseFile = new File(pkg.baseCodePath);
+ long maxModifiedTime = baseFile.lastModified();
+ if (pkg.splitCodePaths != null) {
+ for (int i = pkg.splitCodePaths.length - 1; i >=0; --i) {
+ final File splitFile = new File(pkg.splitCodePaths[i]);
+ maxModifiedTime = Math.max(maxModifiedTime, splitFile.lastModified());
+ }
+ }
+ return maxModifiedTime;
+ }
+ return srcFile.lastModified();
+ }
+
private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg, File srcFile,
final int policyFlags) throws PackageManagerException {
if (ps != null
&& ps.codePath.equals(srcFile)
- && ps.timeStamp == srcFile.lastModified()
+ && ps.timeStamp == getLastModifiedTime(pkg, srcFile)
&& !isCompatSignatureUpdateNeeded(pkg)
&& !isRecoverSignatureUpdateNeeded(pkg)) {
long mSigningKeySetId = ps.keySetData.getProperSigningKeySet();
@@ -8400,7 +8418,7 @@
final String pkgName = pkg.packageName;
- final long scanFileTime = scanFile.lastModified();
+ final long scanFileTime = getLastModifiedTime(pkg, scanFile);
final boolean forceDex = (scanFlags & SCAN_FORCE_DEX) != 0;
pkg.applicationInfo.processName = fixProcessName(
pkg.applicationInfo.packageName,
@@ -9539,6 +9557,10 @@
}
private void killApplication(String pkgName, int appId, String reason) {
+ killApplication(pkgName, appId, UserHandle.USER_ALL, reason);
+ }
+
+ private void killApplication(String pkgName, int appId, int userId, String reason) {
// Request the ActivityManager to kill the process(only for existing packages)
// so that we do not end up in a confused state while the user is still using the older
// version of the application while the new one gets installed.
@@ -9547,7 +9569,7 @@
IActivityManager am = ActivityManagerNative.getDefault();
if (am != null) {
try {
- am.killApplicationWithAppId(pkgName, appId, reason);
+ am.killApplication(pkgName, appId, userId, reason);
} catch (RemoteException e) {
}
}
@@ -12531,13 +12553,12 @@
}
if (mSuccess) {
- final boolean mounted;
- if (Environment.isExternalStorageEmulated()) {
- mounted = true;
- } else {
+ boolean mounted = false;
+ try {
final String status = Environment.getExternalStorageState();
mounted = (Environment.MEDIA_MOUNTED.equals(status)
|| Environment.MEDIA_MOUNTED_READ_ONLY.equals(status));
+ } catch (Exception e) {
}
if (mounted) {
@@ -15139,16 +15160,13 @@
}
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
// Do not run PackageDexOptimizer through the local performDexOpt
- // method because `pkg` is not in `mPackages` yet.
- int result = mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
+ // method because `pkg` may not be in `mPackages` yet.
+ //
+ // Also, don't fail application installs if the dexopt step fails.
+ mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
null /* instructionSets */, false /* checkProfiles */,
getCompilerFilterForReason(REASON_INSTALL));
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
- String msg = "Extracting package failed for " + pkgName;
- res.setError(INSTALL_FAILED_DEXOPT, msg);
- return;
- }
// Notify BackgroundDexOptService that the package has been changed.
// If this is an update of a package which used to fail to compile,
@@ -15564,10 +15582,10 @@
final PackageRemovedInfo info = new PackageRemovedInfo();
final boolean res;
- final UserHandle removeForUser = (deleteFlags & PackageManager.DELETE_ALL_USERS) != 0
- ? UserHandle.ALL : new UserHandle(userId);
+ final int removeUser = (deleteFlags & PackageManager.DELETE_ALL_USERS) != 0
+ ? UserHandle.USER_ALL : userId;
- if (isPackageDeviceAdmin(packageName, removeForUser.getIdentifier())) {
+ if (isPackageDeviceAdmin(packageName, removeUser)) {
Slog.w(TAG, "Not removing package " + packageName + ": has active device admin");
return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
}
@@ -15587,11 +15605,21 @@
info.origUsers = uninstalledPs.queryInstalledUsers(allUsers, true);
}
+ final int freezeUser;
+ if (isUpdatedSystemApp(uninstalledPs)
+ && ((deleteFlags & PackageManager.DELETE_SYSTEM_APP) == 0)) {
+ // We're downgrading a system app, which will apply to all users, so
+ // freeze them all during the downgrade
+ freezeUser = UserHandle.USER_ALL;
+ } else {
+ freezeUser = removeUser;
+ }
+
synchronized (mInstallLock) {
if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageX: pkg=" + packageName + " user=" + userId);
- try (PackageFreezer freezer = freezePackageForDelete(packageName, deleteFlags,
- "deletePackageX")) {
- res = deletePackageLIF(packageName, removeForUser, true, allUsers,
+ try (PackageFreezer freezer = freezePackageForDelete(packageName, freezeUser,
+ deleteFlags, "deletePackageX")) {
+ res = deletePackageLIF(packageName, UserHandle.of(removeUser), true, allUsers,
deleteFlags | REMOVE_CHATTY, info, true, null);
}
synchronized (mPackages) {
@@ -19846,24 +19874,38 @@
}
public PackageFreezer freezePackage(String packageName, String killReason) {
- return new PackageFreezer(packageName, killReason);
+ return freezePackage(packageName, UserHandle.USER_ALL, killReason);
+ }
+
+ public PackageFreezer freezePackage(String packageName, int userId, String killReason) {
+ return new PackageFreezer(packageName, userId, killReason);
}
public PackageFreezer freezePackageForInstall(String packageName, int installFlags,
String killReason) {
+ return freezePackageForInstall(packageName, UserHandle.USER_ALL, installFlags, killReason);
+ }
+
+ public PackageFreezer freezePackageForInstall(String packageName, int userId, int installFlags,
+ String killReason) {
if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
return new PackageFreezer();
} else {
- return freezePackage(packageName, killReason);
+ return freezePackage(packageName, userId, killReason);
}
}
public PackageFreezer freezePackageForDelete(String packageName, int deleteFlags,
String killReason) {
+ return freezePackageForDelete(packageName, UserHandle.USER_ALL, deleteFlags, killReason);
+ }
+
+ public PackageFreezer freezePackageForDelete(String packageName, int userId, int deleteFlags,
+ String killReason) {
if ((deleteFlags & PackageManager.DELETE_DONT_KILL_APP) != 0) {
return new PackageFreezer();
} else {
- return freezePackage(packageName, killReason);
+ return freezePackage(packageName, userId, killReason);
}
}
@@ -19894,14 +19936,14 @@
mCloseGuard.open("close");
}
- public PackageFreezer(String packageName, String killReason) {
+ public PackageFreezer(String packageName, int userId, String killReason) {
synchronized (mPackages) {
mPackageName = packageName;
mWeFroze = mFrozenPackages.add(mPackageName);
final PackageSetting ps = mSettings.mPackages.get(mPackageName);
if (ps != null) {
- killApplication(ps.name, ps.appId, killReason);
+ killApplication(ps.name, ps.appId, userId, killReason);
}
final PackageParser.Package p = mPackages.get(packageName);
@@ -19910,7 +19952,7 @@
mChildren = new PackageFreezer[N];
for (int i = 0; i < N; i++) {
mChildren[i] = new PackageFreezer(p.childPackages.get(i).packageName,
- killReason);
+ userId, killReason);
}
} else {
mChildren = null;
@@ -20049,7 +20091,7 @@
seinfo = pkg.applicationInfo.seinfo;
label = String.valueOf(pm.getApplicationLabel(pkg.applicationInfo));
targetSdkVersion = pkg.applicationInfo.targetSdkVersion;
- freezer = new PackageFreezer(packageName, "movePackageInternal");
+ freezer = freezePackage(packageName, "movePackageInternal");
installedUserIds = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 07dc404..5787bdb 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1099,8 +1099,9 @@
try {
mInterface.setHomeActivity(componentName, userId);
+ pw.println("Success");
return 0;
- } catch (RemoteException e) {
+ } catch (Exception e) {
pw.println(e.toString());
return 1;
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index ace14ac..67e4e93 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -54,8 +54,6 @@
* User information used by {@link ShortcutService}.
*
* All methods should be guarded by {@code #mShortcutUser.mService.mLock}.
- *
- * TODO Max dynamic shortcuts cap should be per activity.
*/
class ShortcutPackage extends ShortcutPackageItem {
private static final String TAG = ShortcutService.TAG;
@@ -321,9 +319,27 @@
/**
* Remove a dynamic shortcut by ID. It'll be removed from the dynamic set, but if the shortcut
* is pinned, it'll remain as a pinned shortcut, and is still enabled.
+ *
+ * @return true if it's actually removed because it wasn't pinned, or false if it's still
+ * pinned.
*/
- public void deleteDynamicWithId(@NonNull String shortcutId) {
- deleteOrDisableWithId(shortcutId, /* disable =*/ false, /* overrideImmutable=*/ false);
+ public boolean deleteDynamicWithId(@NonNull String shortcutId) {
+ final ShortcutInfo removed = deleteOrDisableWithId(
+ shortcutId, /* disable =*/ false, /* overrideImmutable=*/ false);
+ return removed == null;
+ }
+
+ /**
+ * Disable a dynamic shortcut by ID. It'll be removed from the dynamic set, but if the shortcut
+ * is pinned, it'll remain as a pinned shortcut, but will be disabled.
+ *
+ * @return true if it's actually removed because it wasn't pinned, or false if it's still
+ * pinned.
+ */
+ private boolean disableDynamicWithId(@NonNull String shortcutId) {
+ final ShortcutInfo disabled = deleteOrDisableWithId(
+ shortcutId, /* disable =*/ true, /* overrideImmutable=*/ false);
+ return disabled == null;
}
/**
@@ -599,14 +615,14 @@
*
* @return TRUE if any shortcuts have been changed.
*/
- public boolean handlePackageAddedOrUpdated(boolean isNewApp) {
+ public boolean handlePackageAddedOrUpdated(boolean isNewApp, boolean forceRescan) {
final PackageInfo pi = mShortcutUser.mService.getPackageInfo(
getPackageName(), getPackageUserId());
if (pi == null) {
return false; // Shouldn't happen.
}
- if (!isNewApp) {
+ if (!isNewApp && !forceRescan) {
// Make sure the version code or last update time has changed.
// Otherwise, nothing to do.
if (getPackageInfo().getVersionCode() >= pi.versionCode
@@ -649,12 +665,26 @@
boolean changed = false;
// For existing shortcuts, update timestamps if they have any resources.
+ // Also check if shortcuts' activities are still main activities. Otherwise, disable them.
if (!isNewApp) {
Resources publisherRes = null;
for (int i = mShortcuts.size() - 1; i >= 0; i--) {
final ShortcutInfo si = mShortcuts.valueAt(i);
+ if (si.isDynamic()) {
+ if (!s.injectIsMainActivity(si.getActivity(), getPackageUserId())) {
+ Slog.w(TAG, String.format(
+ "%s is no longer main activity. Disabling shorcut %s.",
+ getPackageName(), si.getId()));
+ if (disableDynamicWithId(si.getId())) {
+ continue; // Actually removed.
+ }
+ // Still pinned, so fall-through and possibly update the resources.
+ }
+ changed = true;
+ }
+
if (si.hasAnyResources()) {
if (!si.isOriginallyFromManifest()) {
if (publisherRes == null) {
@@ -682,6 +712,8 @@
changed |= pushOutExcessShortcuts();
}
+ s.verifyStates();
+
if (changed) {
// This will send a notification to the launcher, and also save .
s.packageShortcutsChanged(getPackageName(), getPackageUserId());
@@ -774,6 +806,7 @@
}
removeOrphans();
}
+ adjustRanks();
return changed;
}
@@ -810,7 +843,6 @@
deleteDynamicWithId(shortcut.getId());
}
}
- service.verifyStates();
return changed;
}
@@ -910,9 +942,8 @@
final ComponentName newActivity = newShortcut.getActivity();
if (newActivity == null) {
if (operation != ShortcutService.OPERATION_UPDATE) {
- // This method may be called before validating shortcuts, so this may happen,
- // and is a caller side error.
- throw new NullPointerException("Activity must be provided");
+ service.wtf("Activity must not be null at this point");
+ continue; // Just ignore this invalid case.
}
continue; // Activity can be null for update.
}
diff --git a/services/core/java/com/android/server/pm/ShortcutParser.java b/services/core/java/com/android/server/pm/ShortcutParser.java
index ec19927..858e1cd 100644
--- a/services/core/java/com/android/server/pm/ShortcutParser.java
+++ b/services/core/java/com/android/server/pm/ShortcutParser.java
@@ -21,13 +21,14 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
+import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
-import android.net.Uri;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.Slog;
import android.util.Xml;
@@ -48,22 +49,49 @@
private static final boolean DEBUG = ShortcutService.DEBUG || false; // DO NOT SUBMIT WITH TRUE
@VisibleForTesting
- static final String METADATA_KEY = "android.pm.Shortcuts";
+ static final String METADATA_KEY = "android.app.shortcuts";
private static final String TAG_SHORTCUTS = "shortcuts";
private static final String TAG_SHORTCUT = "shortcut";
+ private static final String TAG_INTENT = "intent";
+ private static final String TAG_CATEGORIES = "categories";
@Nullable
public static List<ShortcutInfo> parseShortcuts(ShortcutService service,
String packageName, @UserIdInt int userId) throws IOException, XmlPullParserException {
- final PackageInfo pi = service.injectGetActivitiesWithMetadata(packageName, userId);
+ if (ShortcutService.DEBUG) {
+ Slog.d(TAG, String.format("Scanning package %s for manifest shortcuts on user %d",
+ packageName, userId));
+ }
+ final List<ResolveInfo> activities = service.injectGetMainActivities(packageName, userId);
+ if (activities == null || activities.size() == 0) {
+ return null;
+ }
List<ShortcutInfo> result = null;
- if (pi != null && pi.activities != null) {
- for (ActivityInfo activityInfo : pi.activities) {
- result = parseShortcutsOneFile(service, activityInfo, packageName, userId, result);
+ try {
+ final int size = activities.size();
+ for (int i = 0; i < size; i++) {
+ final ActivityInfo activityInfoNoMetadata = activities.get(i).activityInfo;
+ if (activityInfoNoMetadata == null) {
+ continue;
+ }
+
+ final ActivityInfo activityInfoWithMetadata =
+ service.injectGetActivityInfoWithMetadata(
+ activityInfoNoMetadata.getComponentName(), userId);
+ if (activityInfoWithMetadata != null) {
+ result = parseShortcutsOneFile(
+ service, activityInfoWithMetadata, packageName, userId, result);
+ }
}
+ } catch (RuntimeException e) {
+ // Resource ID mismatch may cause various runtime exceptions when parsing XMLs,
+ // But we don't crash the device, so just swallow them.
+ service.wtf(
+ "Exception caught while parsing shortcut XML for package=" + packageName, e);
+ return null;
}
return result;
}
@@ -72,6 +100,11 @@
ShortcutService service,
ActivityInfo activityInfo, String packageName, @UserIdInt int userId,
List<ShortcutInfo> result) throws IOException, XmlPullParserException {
+ if (ShortcutService.DEBUG) {
+ Slog.d(TAG, String.format(
+ "Checking main activity %s", activityInfo.getComponentName()));
+ }
+
XmlResourceParser parser = null;
try {
parser = service.injectXmlMetaData(activityInfo, METADATA_KEY);
@@ -89,14 +122,58 @@
final int maxShortcuts = service.getMaxActivityShortcuts();
int numShortcuts = 0;
+ // We instantiate ShortcutInfo at <shortcut>, but we add it to the list at </shortcut>,
+ // after parsing <intent>. We keep the current one in here.
+ ShortcutInfo currentShortcut = null;
+
+ Set<String> categories = null;
+
outer:
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > 0)) {
+ final int depth = parser.getDepth();
+ final String tag = parser.getName();
+
+ // When a shortcut tag is closing, publish.
+ if ((type == XmlPullParser.END_TAG) && (depth == 2) && (TAG_SHORTCUT.equals(tag))) {
+ if (currentShortcut == null) {
+ // Shortcut was invalid.
+ continue;
+ }
+ final ShortcutInfo si = currentShortcut;
+ currentShortcut = null; // Make sure to null out for the next iteration.
+
+ if (si.getIntent() == null) {
+ Log.e(TAG, "Shortcut " + si.getId() + " has no intent. Skipping it.");
+ continue;
+ }
+
+ if (numShortcuts >= maxShortcuts) {
+ Log.e(TAG, "More than " + maxShortcuts + " shortcuts found for "
+ + activityInfo.getComponentName() + ". Skipping the rest.");
+ return result;
+ }
+ if (categories != null) {
+ si.setCategories(categories);
+ categories = null;
+ }
+
+ if (result == null) {
+ result = new ArrayList<>();
+ }
+ result.add(si);
+ numShortcuts++;
+ rank++;
+ if (ShortcutService.DEBUG) {
+ Slog.d(TAG, "Shortcut added: " + si.toInsecureString());
+ }
+ continue;
+ }
+
+ // Otherwise, just look at start tags.
if (type != XmlPullParser.START_TAG) {
continue;
}
- final int depth = parser.getDepth();
- final String tag = parser.getName();
if (depth == 1 && TAG_SHORTCUTS.equals(tag)) {
continue; // Root tag.
@@ -104,35 +181,73 @@
if (depth == 2 && TAG_SHORTCUT.equals(tag)) {
final ShortcutInfo si = parseShortcutAttributes(
service, attrs, packageName, activity, userId, rank);
+ if (si == null) {
+ // Shortcut was invalid.
+ continue;
+ }
if (ShortcutService.DEBUG) {
- Slog.d(TAG, "Shortcut=" + si);
+ Slog.d(TAG, "Shortcut found: " + si.toInsecureString());
}
if (result != null) {
for (int i = result.size() - 1; i >= 0; i--) {
if (si.getId().equals(result.get(i).getId())) {
- Slog.w(TAG, "Duplicate shortcut ID detected, skipping.");
+ Log.e(TAG, "Duplicate shortcut ID detected. Skipping it.");
continue outer;
}
}
}
+ if (!si.isEnabled()) {
+ // Just set the default intent to disabled shortcuts.
+ si.setIntent(new Intent(Intent.ACTION_VIEW));
+ }
+ currentShortcut = si;
+ categories = null;
+ continue;
+ }
+ if (depth == 3 && TAG_INTENT.equals(tag)) {
+ if ((currentShortcut == null)
+ || (currentShortcut.getIntentNoExtras() != null)
+ || !currentShortcut.isEnabled()) {
+ Log.e(TAG, "Ignoring excessive intent tag.");
+ continue;
+ }
- if (si != null) {
- if (numShortcuts >= maxShortcuts) {
- Slog.w(TAG, "More than " + maxShortcuts + " shortcuts found for "
- + activityInfo.getComponentName() + ", ignoring the rest.");
- return result;
- }
-
- if (result == null) {
- result = new ArrayList<>();
- }
- result.add(si);
- numShortcuts++;
- rank++;
+ final Intent intent = Intent.parseIntent(service.mContext.getResources(),
+ parser, attrs);
+ if (TextUtils.isEmpty(intent.getAction())) {
+ Log.e(TAG, "Shortcut intent action must be provided. activity=" + activity);
+ continue;
+ }
+ try {
+ currentShortcut.setIntent(intent);
+ } catch (RuntimeException e) {
+ // This shouldn't happen because intents in XML can't have complicated
+ // extras, but just in case Intent.parseIntent() supports such a thing one
+ // day.
+ Log.e(TAG, "Shortcut's extras contain un-persistable values. Skipping it.");
+ continue;
}
continue;
}
- Slog.w(TAG, "Unknown tag " + tag);
+ if (depth == 3 && TAG_CATEGORIES.equals(tag)) {
+ if ((currentShortcut == null)
+ || (currentShortcut.getCategories() != null)) {
+ continue;
+ }
+ final String name = parseCategories(service, attrs);
+ if (TextUtils.isEmpty(name)) {
+ Log.e(TAG, "Empty category found. activity=" + activity);
+ continue;
+ }
+
+ if (categories == null) {
+ categories = new ArraySet<>();
+ }
+ categories.add(name);
+ continue;
+ }
+
+ ShortcutService.warnForInvalidTag(depth, tag);
}
} finally {
if (parser != null) {
@@ -142,6 +257,16 @@
return result;
}
+ private static String parseCategories(ShortcutService service, AttributeSet attrs) {
+ final TypedArray sa = service.mContext.getResources().obtainAttributes(attrs,
+ R.styleable.ShortcutCategories);
+ try {
+ return sa.getString(R.styleable.ShortcutCategories_name);
+ } finally {
+ sa.recycle();
+ }
+ }
+
private static ShortcutInfo parseShortcutAttributes(ShortcutService service,
AttributeSet attrs, String packageName, ComponentName activity,
@UserIdInt int userId, int rank) {
@@ -150,14 +275,11 @@
try {
final String id = sa.getString(R.styleable.Shortcut_shortcutId);
final boolean enabled = sa.getBoolean(R.styleable.Shortcut_enabled, true);
- final int iconResId = sa.getResourceId(R.styleable.Shortcut_shortcutIcon, 0);
+ final int iconResId = sa.getResourceId(R.styleable.Shortcut_icon, 0);
final int titleResId = sa.getResourceId(R.styleable.Shortcut_shortcutShortLabel, 0);
final int textResId = sa.getResourceId(R.styleable.Shortcut_shortcutLongLabel, 0);
final int disabledMessageResId = sa.getResourceId(
R.styleable.Shortcut_shortcutDisabledMessage, 0);
- final String categories = sa.getString(R.styleable.Shortcut_shortcutCategories);
- String intentAction = sa.getString(R.styleable.Shortcut_shortcutIntentAction);
- final String intentData = sa.getString(R.styleable.Shortcut_shortcutIntentData);
if (TextUtils.isEmpty(id)) {
Slog.w(TAG, "Shortcut ID must be provided. activity=" + activity);
@@ -167,31 +289,6 @@
Slog.w(TAG, "Shortcut title must be provided. activity=" + activity);
return null;
}
- if (TextUtils.isEmpty(intentAction)) {
- if (enabled) {
- Slog.w(TAG, "Shortcut intent action must be provided. activity=" + activity);
- return null;
- } else {
- // Disabled shortcut doesn't have to have an action, but just set VIEW as the
- // default.
- intentAction = Intent.ACTION_VIEW;
- }
- }
-
- final ArraySet<String> categoriesSet;
- if (categories == null) {
- categoriesSet = null;
- } else {
- final String[] arr = categories.split(":");
- categoriesSet = new ArraySet<>(arr.length);
- for (String v : arr) {
- categoriesSet.add(v);
- }
- }
- final Intent intent = new Intent(intentAction);
- if (!TextUtils.isEmpty(intentData)) {
- intent.setData(Uri.parse(intentData));
- }
return createShortcutFromManifest(
service,
@@ -202,8 +299,6 @@
titleResId,
textResId,
disabledMessageResId,
- categoriesSet,
- intent,
rank,
iconResId,
enabled);
@@ -214,8 +309,8 @@
private static ShortcutInfo createShortcutFromManifest(ShortcutService service,
@UserIdInt int userId, String id, String packageName, ComponentName activityComponent,
- int titleResId, int textResId, int disabledMessageResId, Set<String> categories,
- Intent intent, int rank, int iconResId, boolean enabled) {
+ int titleResId, int textResId, int disabledMessageResId,
+ int rank, int iconResId, boolean enabled) {
final int flags =
(enabled ? ShortcutInfo.FLAG_MANIFEST : ShortcutInfo.FLAG_DISABLED)
@@ -239,8 +334,8 @@
null, // disabled message string
disabledMessageResId,
null, // disabled message res name
- categories,
- intent,
+ null, // categories
+ null, // intent
null, // intent extras
rank,
null, // extras
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 16191687..1db1ce7 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -60,6 +60,7 @@
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.SELinux;
+import android.os.ServiceManager;
import android.os.ShellCommand;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -76,6 +77,7 @@
import android.util.SparseLongArray;
import android.util.TypedValue;
import android.util.Xml;
+import android.view.IWindowManager;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -123,28 +125,15 @@
* - Deal with the async nature of PACKAGE_ADD. Basically when a publisher does anything after
* it's upgraded, the manager should make sure the upgrade process has been executed.
*
- * - HandleUnlockUser needs to be async. Wait on it in onCleanupUser.
- *
- * - Implement reportShortcutUsed().
- *
- * - validateForXml() should be removed.
- *
- * - Ranks should be recalculated after each update.
- *
- * - When the system locale changes, update timestamps for shortcuts with string resources,
- * and notify the launcher. Right now, it resets the throttling, but timestamps are not changed
- * and there's no notification either.
- *
* - getIconMaxWidth()/getIconMaxHeight() should use xdpi and ydpi.
+ * -> But TypedValue.applyDimension() doesn't differentiate x and y..?
*
* - Default launcher check does take a few ms. Worth caching.
*
* - Detect when already registered instances are passed to APIs again, which might break
- * internal bitmap handling.
+ * internal bitmap handling.
*
* - Add more call stats.
- *
- * - Rename mMaxDynamicShortcuts, because it includes manifest shortcuts too.
*/
public class ShortcutService extends IShortcutService.Stub {
static final String TAG = "ShortcutService";
@@ -194,6 +183,8 @@
private static final String ATTR_VALUE = "value";
+ private static final String LAUNCHER_INTENT_CATEGORY = Intent.CATEGORY_LAUNCHER;
+
@VisibleForTesting
interface ConfigConstants {
/**
@@ -256,9 +247,9 @@
private final SparseArray<ShortcutUser> mUsers = new SparseArray<>();
/**
- * Max number of dynamic shortcuts that each application can have at a time.
+ * Max number of dynamic + manifest shortcuts that each application can have at a time.
*/
- private int mMaxDynamicShortcuts;
+ private int mMaxShortcuts;
/**
* Max number of updating API calls that each application can make during the interval.
@@ -295,7 +286,8 @@
private List<Integer> mDirtyUserIds = new ArrayList<>();
/**
- * A counter that increments every time the system locale changes. We keep track of it to reset
+ * A counter that increments every time the system locale changes. We keep track of it to
+ * reset
* throttling counters on the first call from each package after the last locale change.
*
* We need this mechanism because we can't do much in the locale change callback, which is
@@ -307,8 +299,8 @@
private static final int PACKAGE_MATCH_FLAGS =
PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_UNINSTALLED_PACKAGES;
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.MATCH_UNINSTALLED_PACKAGES;
// Stats
@VisibleForTesting
@@ -319,13 +311,15 @@
int GET_APPLICATION_INFO = 3;
int LAUNCHER_PERMISSION_CHECK = 4;
int CLEANUP_DANGLING_BITMAPS = 5;
- int GET_ACTIVITIES_WITH_METADATA = 6;
+ int GET_ACTIVITY_WITH_METADATA = 6;
int GET_INSTALLED_PACKAGES = 7;
int CHECK_PACKAGE_CHANGES = 8;
int GET_APPLICATION_RESOURCES = 9;
int RESOURCE_NAME_LOOKUP = 10;
+ int GET_LAUNCHER_ACTIVITY = 11;
+ int CHECK_LAUNCHER_ACTIVITY = 12;
- int COUNT = RESOURCE_NAME_LOOKUP + 1;
+ int COUNT = CHECK_LAUNCHER_ACTIVITY + 1;
}
final Object mStatLock = new Object();
@@ -348,9 +342,10 @@
OPERATION_SET,
OPERATION_ADD,
OPERATION_UPDATE
- })
+ })
@Retention(RetentionPolicy.SOURCE)
- @interface ShortcutOperation {}
+ @interface ShortcutOperation {
+ }
public ShortcutService(Context context) {
this(context, BackgroundThread.get().getLooper());
@@ -386,18 +381,22 @@
}
final private IUidObserver mUidObserver = new IUidObserver.Stub() {
- @Override public void onUidStateChanged(int uid, int procState) throws RemoteException {
+ @Override
+ public void onUidStateChanged(int uid, int procState) throws RemoteException {
handleOnUidStateChanged(uid, procState);
}
- @Override public void onUidGone(int uid) throws RemoteException {
+ @Override
+ public void onUidGone(int uid) throws RemoteException {
handleOnUidStateChanged(uid, ActivityManager.MAX_PROCESS_STATE);
}
- @Override public void onUidActive(int uid) throws RemoteException {
+ @Override
+ public void onUidActive(int uid) throws RemoteException {
}
- @Override public void onUidIdle(int uid) throws RemoteException {
+ @Override
+ public void onUidIdle(int uid) throws RemoteException {
}
};
@@ -563,16 +562,16 @@
mMaxUpdatesPerInterval = Math.max(0, (int) parser.getLong(
ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL, DEFAULT_MAX_UPDATES_PER_INTERVAL));
- mMaxDynamicShortcuts = Math.max(0, (int) parser.getLong(
+ mMaxShortcuts = Math.max(0, (int) parser.getLong(
ConfigConstants.KEY_MAX_SHORTCUTS, DEFAULT_MAX_SHORTCUTS_PER_APP));
final int iconDimensionDp = Math.max(1, injectIsLowRamDevice()
? (int) parser.getLong(
- ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM,
- DEFAULT_MAX_ICON_DIMENSION_LOWRAM_DP)
+ ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM,
+ DEFAULT_MAX_ICON_DIMENSION_LOWRAM_DP)
: (int) parser.getLong(
- ConfigConstants.KEY_MAX_ICON_DIMENSION_DP,
- DEFAULT_MAX_ICON_DIMENSION_DP));
+ ConfigConstants.KEY_MAX_ICON_DIMENSION_DP,
+ DEFAULT_MAX_ICON_DIMENSION_DP));
mMaxIconDimension = injectDipToPixel(iconDimensionDp);
@@ -647,15 +646,19 @@
@Nullable
static Intent parseIntentAttribute(XmlPullParser parser, String attribute) {
final String value = parseStringAttribute(parser, attribute);
- if (TextUtils.isEmpty(value)) {
- return null;
+ Intent parsed = null;
+ if (!TextUtils.isEmpty(value)) {
+ try {
+ parsed = Intent.parseUri(value, /* flags =*/ 0);
+ } catch (URISyntaxException e) {
+ Slog.e(TAG, "Error parsing intent", e);
+ }
}
- try {
- return Intent.parseUri(value, /* flags =*/ 0);
- } catch (URISyntaxException e) {
- Slog.e(TAG, "Error parsing intent", e);
- return null;
+ if (parsed == null) {
+ // Default intent.
+ parsed = new Intent(Intent.ACTION_VIEW);
}
+ return parsed;
}
static void writeTagValue(XmlSerializer out, String tag, String value) throws IOException {
@@ -786,7 +789,7 @@
}
} catch (FileNotFoundException e) {
// Use the default
- } catch (IOException|XmlPullParserException e) {
+ } catch (IOException | XmlPullParserException e) {
Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
mRawLastResetTime = 0;
@@ -809,7 +812,7 @@
saveUserInternalLocked(userId, os, /* forBackup= */ false);
file.finishWrite(os);
- } catch (XmlPullParserException|IOException e) {
+ } catch (XmlPullParserException | IOException e) {
Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
file.failWrite(os);
}
@@ -859,10 +862,10 @@
return null;
}
try {
- final ShortcutUser ret = loadUserInternal(userId, in, /* forBackup= */ false);
+ final ShortcutUser ret = loadUserInternal(userId, in, /* forBackup= */ false);
cleanupDanglingBitmapDirectoriesLocked(userId, ret);
return ret;
- } catch (IOException|XmlPullParserException e) {
+ } catch (IOException | XmlPullParserException e) {
Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
return null;
} finally {
@@ -1142,7 +1145,7 @@
}
final String baseName = String.valueOf(injectCurrentTimeMillis());
- for (int suffix = 0;; suffix++) {
+ for (int suffix = 0; ; suffix++) {
final String filename = (suffix == 0 ? baseName : baseName + "_" + suffix) + ".png";
final File file = new File(packagePath, filename);
if (!file.exists()) {
@@ -1214,7 +1217,7 @@
} finally {
IoUtils.closeQuietly(out);
}
- } catch (IOException|RuntimeException e) {
+ } catch (IOException | RuntimeException e) {
// STOPSHIP Change wtf to e
Slog.wtf(ShortcutService.TAG, "Unable to write bitmap to file", e);
if (path != null && path.exists()) {
@@ -1293,7 +1296,7 @@
private boolean isCallerSystem() {
final int callingUid = injectBinderCallingUid();
- return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
+ return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
}
private boolean isCallerShell() {
@@ -1358,10 +1361,10 @@
/**
* @throws IllegalArgumentException if {@code numShortcuts} is bigger than
- * {@link #getMaxActivityShortcuts()}.
+ * {@link #getMaxActivityShortcuts()}.
*/
void enforceMaxActivityShortcuts(int numShortcuts) {
- if (numShortcuts > mMaxDynamicShortcuts) {
+ if (numShortcuts > mMaxShortcuts) {
throw new IllegalArgumentException("Max number of dynamic shortcuts exceeded");
}
}
@@ -1370,7 +1373,7 @@
* Return the max number of dynamic + manifest shortcuts for each launcher icon.
*/
int getMaxActivityShortcuts() {
- return mMaxDynamicShortcuts;
+ return mMaxShortcuts;
}
/**
@@ -1411,7 +1414,7 @@
* Clean up / validate an incoming shortcut.
* - Make sure all mandatory fields are set.
* - Make sure the intent's extras are persistable, and them to set
- * {@link ShortcutInfo#mIntentPersistableExtras}. Also clear its extras.
+ * {@link ShortcutInfo#mIntentPersistableExtras}. Also clear its extras.
* - Clear flags.
*
* TODO Detailed unit tests
@@ -1421,63 +1424,43 @@
if (shortcut.getActivity() != null) {
Preconditions.checkState(
shortcut.getPackage().equals(shortcut.getActivity().getPackageName()),
- "Activity package name mismatch");
+ "Cannot publish shortcut: activity " + shortcut.getActivity() + " does not"
+ + " belong to package " + shortcut.getPackage());
}
if (!forUpdate) {
shortcut.enforceMandatoryFields();
+ Preconditions.checkArgument(
+ injectIsMainActivity(shortcut.getActivity(), shortcut.getUserId()),
+ "Cannot publish shortcut: " + shortcut.getActivity() + " is not main activity");
}
if (shortcut.getIcon() != null) {
ShortcutInfo.validateIcon(shortcut.getIcon());
}
- validateForXml(shortcut.getId());
- validateForXml(shortcut.getTitle());
- validatePersistableBundleForXml(shortcut.getIntentPersistableExtras());
- validatePersistableBundleForXml(shortcut.getExtras());
-
shortcut.replaceFlags(0);
}
- // KXmlSerializer is strict and doesn't allow certain characters, so we disallow those
- // characters.
+ /**
+ * When a shortcut has no target activity, set the default one from the package.
+ */
+ private void fillInDefaultActivity(List<ShortcutInfo> shortcuts) {
- private static void validatePersistableBundleForXml(PersistableBundle b) {
- if (b == null || b.size() == 0) {
- return;
- }
- for (String key : b.keySet()) {
- validateForXml(key);
- final Object value = b.get(key);
- if (value == null) {
- continue;
- } else if (value instanceof String) {
- validateForXml((String) value);
- } else if (value instanceof String[]) {
- for (String v : (String[]) value) {
- validateForXml(v);
+ ComponentName defaultActivity = null;
+ for (int i = shortcuts.size() - 1; i >= 0; i--) {
+ final ShortcutInfo si = shortcuts.get(i);
+ if (si.getActivity() == null) {
+ if (defaultActivity == null) {
+ defaultActivity = injectGetDefaultMainActivity(
+ si.getPackage(), si.getUserId());
+ Preconditions.checkState(defaultActivity != null,
+ "Launcher activity not found for package " + si.getPackage());
}
- } else if (value instanceof PersistableBundle) {
- validatePersistableBundleForXml((PersistableBundle) value);
+ si.setActivity(defaultActivity);
}
}
}
- private static void validateForXml(CharSequence s) {
- if (TextUtils.isEmpty(s)) {
- return;
- }
- for (int i = s.length() - 1; i >= 0; i--) {
- if (!isAllowedInXml(s.charAt(i))) {
- throw new IllegalArgumentException("Unsupported character detected in: " + s);
- }
- }
- }
-
- private static boolean isAllowedInXml(char c) {
- return (c >= 0x20 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xfffd);
- }
-
private void assignImplicitRanks(List<ShortcutInfo> shortcuts) {
for (int i = shortcuts.size() - 1; i >= 0; i--) {
shortcuts.get(i).setImplicitRank(i);
@@ -1499,6 +1482,8 @@
ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
+ fillInDefaultActivity(newShortcuts);
+
ps.enforceShortcutCountsBeforeOperation(newShortcuts, OPERATION_SET);
// Throttling.
@@ -1510,6 +1495,10 @@
ps.clearAllImplicitRanks();
assignImplicitRanks(newShortcuts);
+ for (int i = 0; i < size; i++) {
+ fixUpIncomingShortcutInfo(newShortcuts.get(i), /* forUpdate= */ false);
+ }
+
// First, remove all un-pinned; dynamic shortcuts
ps.deleteAllDynamicShortcuts();
@@ -1542,6 +1531,9 @@
ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
+ // For update, don't fill in the default activity. Having null activity means
+ // "don't update the activity" here.
+
ps.enforceShortcutCountsBeforeOperation(newShortcuts, OPERATION_UPDATE);
// Throttling.
@@ -1622,6 +1614,8 @@
ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
+ fillInDefaultActivity(newShortcuts);
+
ps.enforceShortcutCountsBeforeOperation(newShortcuts, OPERATION_ADD);
// Initialize the implicit ranks for ShortcutPackage.adjustRanks().
@@ -1780,11 +1774,11 @@
}
@Override
- public int getMaxDynamicShortcutCount(String packageName, @UserIdInt int userId)
+ public int getMaxShortcutCountForActivity(String packageName, @UserIdInt int userId)
throws RemoteException {
verifyCaller(packageName, userId);
- return mMaxDynamicShortcuts;
+ return mMaxShortcuts;
}
@Override
@@ -1844,7 +1838,8 @@
}
/**
- * Reset all throttling, for developer options and command line. Only system/shell can call it.
+ * Reset all throttling, for developer options and command line. Only system/shell can call
+ * it.
*/
@Override
public void resetThrottling() {
@@ -1966,10 +1961,12 @@
// === House keeping ===
- private void cleanUpPackageForAllLoadedUsers(String packageName, @UserIdInt int packageUserId) {
+ private void cleanUpPackageForAllLoadedUsers(String packageName, @UserIdInt int packageUserId,
+ boolean appStillExists) {
synchronized (mLock) {
forEachLoadedUserLocked(user ->
- cleanUpPackageLocked(packageName, user.getUserId(), packageUserId));
+ cleanUpPackageLocked(packageName, user.getUserId(), packageUserId,
+ appStillExists));
}
}
@@ -1981,7 +1978,8 @@
* This is called when an app is uninstalled, or an app gets "clear data"ed.
*/
@VisibleForTesting
- void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId) {
+ void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId,
+ boolean appStillExists) {
final boolean wasUserLoaded = isUserLoadedLocked(owningUserId);
final ShortcutUser user = getUserShortcutsLocked(owningUserId);
@@ -2010,6 +2008,13 @@
notifyListeners(packageName, owningUserId);
}
+ // If the app still exists (i.e. data cleared), we need to re-publish manifest shortcuts.
+ if (appStillExists && (packageUserId == owningUserId)) {
+ // This will do the notification and save when needed, so do it after the above
+ // notifyListeners.
+ user.handlePackageAddedOrUpdated(packageName, /* forceRescan=*/ true);
+ }
+
if (!wasUserLoaded) {
// Note this will execute the scheduled save.
unloadUserLocked(owningUserId);
@@ -2318,19 +2323,29 @@
public void onPackageDataCleared(String packageName, int uid) {
handlePackageDataCleared(packageName, getChangingUserId());
}
+
+ @Override
+ public boolean onPackageChanged(String packageName, int uid, String[] components) {
+ handlePackageChanged(packageName, getChangingUserId());
+ return false; // We don't need to receive onSomePackagesChanged(), so just false.
+ }
};
/**
* Called when a user is unlocked.
* - Check all known packages still exist, and otherwise perform cleanup.
* - If a package still exists, check the version code. If it's been updated, may need to
- * update timestamps of its shortcuts.
+ * update timestamps of its shortcuts.
*/
@VisibleForTesting
void checkPackageChanges(@UserIdInt int ownerUserId) {
if (DEBUG) {
Slog.d(TAG, "checkPackageChanges() ownerUserId=" + ownerUserId);
}
+ if (injectIsSafeModeEnabled()) {
+ Slog.i(TAG, "Safe mode, skipping checkPackageChanges()");
+ return;
+ }
final long start = injectElapsedRealtime();
try {
@@ -2351,14 +2366,15 @@
if (gonePackages.size() > 0) {
for (int i = gonePackages.size() - 1; i >= 0; i--) {
final PackageWithUser pu = gonePackages.get(i);
- cleanUpPackageLocked(pu.packageName, ownerUserId, pu.userId);
+ cleanUpPackageLocked(pu.packageName, ownerUserId, pu.userId,
+ /* appStillExists = */ false);
}
}
final long now = injectCurrentTimeMillis();
// Then for each installed app, publish manifest shortcuts when needed.
forUpdatedPackages(ownerUserId, user.getLastAppScanTime(), ai -> {
- user.handlePackageAddedOrUpdated(ai.packageName);
+ user.handlePackageAddedOrUpdated(ai.packageName, /* forceRescan=*/ false);
});
// Write the time just before the scan, because there may be apps that have just
@@ -2379,7 +2395,7 @@
synchronized (mLock) {
final ShortcutUser user = getUserShortcutsLocked(userId);
user.attemptToRestoreIfNeededAndSave(this, packageName, userId);
- user.handlePackageAddedOrUpdated(packageName);
+ user.handlePackageAddedOrUpdated(packageName, /* forceRescan=*/ false);
}
verifyStates();
}
@@ -2394,7 +2410,7 @@
user.attemptToRestoreIfNeededAndSave(this, packageName, userId);
if (isPackageInstalled(packageName, userId)) {
- user.handlePackageAddedOrUpdated(packageName);
+ user.handlePackageAddedOrUpdated(packageName, /* forceRescan=*/ false);
}
}
verifyStates();
@@ -2405,7 +2421,7 @@
Slog.d(TAG, String.format("handlePackageRemoved: %s user=%d", packageName,
packageUserId));
}
- cleanUpPackageForAllLoadedUsers(packageName, packageUserId);
+ cleanUpPackageForAllLoadedUsers(packageName, packageUserId, /* appStillExists = */ false);
verifyStates();
}
@@ -2415,7 +2431,23 @@
Slog.d(TAG, String.format("handlePackageDataCleared: %s user=%d", packageName,
packageUserId));
}
- cleanUpPackageForAllLoadedUsers(packageName, packageUserId);
+ cleanUpPackageForAllLoadedUsers(packageName, packageUserId, /* appStillExists = */ true);
+
+ verifyStates();
+ }
+
+ private void handlePackageChanged(String packageName, int packageUserId) {
+ if (DEBUG) {
+ Slog.d(TAG, String.format("handlePackageChanged: %s user=%d", packageName,
+ packageUserId));
+ }
+
+ // Activities may be disabled or enabled. Just rescan the package.
+ synchronized (mLock) {
+ final ShortcutUser user = getUserShortcutsLocked(packageUserId);
+
+ user.handlePackageAddedOrUpdated(packageName, /* forceRescan=*/ true);
+ }
verifyStates();
}
@@ -2454,7 +2486,7 @@
final long token = injectClearCallingIdentity();
try {
return mIPackageManager.getPackageInfo(packageName, PACKAGE_MATCH_FLAGS
- | (getSignatures ? PackageManager.GET_SIGNATURES : 0)
+ | (getSignatures ? PackageManager.GET_SIGNATURES : 0)
, userId);
} catch (RemoteException e) {
// Shouldn't happen.
@@ -2488,14 +2520,12 @@
}
@Nullable
- @VisibleForTesting
- PackageInfo injectGetActivitiesWithMetadata(String packageName, @UserIdInt int userId) {
+ ActivityInfo injectGetActivityInfoWithMetadata(ComponentName activity, @UserIdInt int userId) {
final long start = injectElapsedRealtime();
final long token = injectClearCallingIdentity();
try {
- return mIPackageManager.getPackageInfo(packageName,
- PACKAGE_MATCH_FLAGS | PackageManager.GET_ACTIVITIES
- | PackageManager.GET_META_DATA, userId);
+ return mIPackageManager.getActivityInfo(activity,
+ PACKAGE_MATCH_FLAGS | PackageManager.GET_META_DATA, userId);
} catch (RemoteException e) {
// Shouldn't happen.
Slog.wtf(TAG, "RemoteException", e);
@@ -2503,7 +2533,7 @@
} finally {
injectRestoreCallingIdentity(token);
- logDurationStat(Stats.GET_ACTIVITIES_WITH_METADATA, start);
+ logDurationStat(Stats.GET_ACTIVITY_WITH_METADATA, start);
}
}
@@ -2580,6 +2610,86 @@
}
}
+ private Intent getMainActivityIntent() {
+ final Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(LAUNCHER_INTENT_CATEGORY);
+ return intent;
+ }
+
+ @Nullable
+ ComponentName injectGetDefaultMainActivity(@NonNull String packageName, int userId) {
+ final long start = injectElapsedRealtime();
+ final long token = injectClearCallingIdentity();
+ try {
+ final Intent intent = getMainActivityIntent();
+ intent.setPackage(packageName);
+
+ final List<ResolveInfo> resolved =
+ mContext.getPackageManager().queryIntentActivitiesAsUser(
+ intent, PACKAGE_MATCH_FLAGS, userId);
+
+ return (resolved == null || resolved.size() == 0)
+ ? null : resolved.get(0).activityInfo.getComponentName();
+ } finally {
+ injectRestoreCallingIdentity(token);
+
+ logDurationStat(Stats.GET_LAUNCHER_ACTIVITY, start);
+ }
+ }
+
+ boolean injectIsMainActivity(@NonNull ComponentName activity, int userId) {
+ final long start = injectElapsedRealtime();
+ final long token = injectClearCallingIdentity();
+ try {
+ final Intent intent = getMainActivityIntent();
+ intent.setPackage(activity.getPackageName());
+ intent.setComponent(activity);
+
+ final List<ResolveInfo> resolved =
+ mContext.getPackageManager().queryIntentActivitiesAsUser(
+ intent, PACKAGE_MATCH_FLAGS, userId);
+
+ return resolved != null && resolved.size() > 0;
+ } finally {
+ injectRestoreCallingIdentity(token);
+
+ logDurationStat(Stats.CHECK_LAUNCHER_ACTIVITY, start);
+ }
+ }
+
+ @NonNull
+ List<ResolveInfo> injectGetMainActivities(@NonNull String packageName, int userId) {
+ final long start = injectElapsedRealtime();
+ final long token = injectClearCallingIdentity();
+ try {
+ final Intent intent = getMainActivityIntent();
+ intent.setPackage(packageName);
+
+ final List<ResolveInfo> resolved =
+ mContext.getPackageManager().queryIntentActivitiesAsUser(
+ intent, PACKAGE_MATCH_FLAGS, userId);
+
+ return (resolved != null) ? resolved : new ArrayList<>(0);
+ } finally {
+ injectRestoreCallingIdentity(token);
+
+ logDurationStat(Stats.CHECK_LAUNCHER_ACTIVITY, start);
+ }
+ }
+
+ boolean injectIsSafeModeEnabled() {
+ final long token = injectClearCallingIdentity();
+ try {
+ return IWindowManager.Stub
+ .asInterface(ServiceManager.getService(Context.WINDOW_SERVICE))
+ .isSafeModeEnabled();
+ } catch (RemoteException e) {
+ return false; // Shouldn't happen though.
+ } finally {
+ injectRestoreCallingIdentity(token);
+ }
+ }
+
// === Backup & restore ===
boolean shouldBackupApp(String packageName, int userId) {
@@ -2609,7 +2719,7 @@
final ByteArrayOutputStream os = new ByteArrayOutputStream(32 * 1024);
try {
saveUserInternalLocked(userId, os, /* forBackup */ true);
- } catch (XmlPullParserException|IOException e) {
+ } catch (XmlPullParserException | IOException e) {
// Shouldn't happen.
Slog.w(TAG, "Backup failed.", e);
return null;
@@ -2628,7 +2738,7 @@
final ByteArrayInputStream is = new ByteArrayInputStream(payload);
try {
user = loadUserInternal(userId, is, /* fromBackup */ true);
- } catch (XmlPullParserException|IOException e) {
+ } catch (XmlPullParserException | IOException e) {
Slog.w(TAG, "Restoration failed.", e);
return;
}
@@ -2705,8 +2815,8 @@
pw.println(mResetInterval);
pw.print(" maxUpdatesPerInterval: ");
pw.println(mMaxUpdatesPerInterval);
- pw.print(" maxDynamicShortcuts: ");
- pw.println(mMaxDynamicShortcuts);
+ pw.print(" maxShortcutsPerActivity: ");
+ pw.println(mMaxShortcuts);
pw.println();
pw.println(" Stats:");
@@ -2719,11 +2829,13 @@
dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO_WITH_SIG, "getPackageInfo(SIG)");
dumpStatLS(pw, p, Stats.GET_APPLICATION_INFO, "getApplicationInfo");
dumpStatLS(pw, p, Stats.CLEANUP_DANGLING_BITMAPS, "cleanupDanglingBitmaps");
- dumpStatLS(pw, p, Stats.GET_ACTIVITIES_WITH_METADATA, "getActivities+metadata");
+ dumpStatLS(pw, p, Stats.GET_ACTIVITY_WITH_METADATA, "getActivity+metadata");
dumpStatLS(pw, p, Stats.GET_INSTALLED_PACKAGES, "getInstalledPackages");
dumpStatLS(pw, p, Stats.CHECK_PACKAGE_CHANGES, "checkPackageChanges");
dumpStatLS(pw, p, Stats.GET_APPLICATION_RESOURCES, "getApplicationResources");
dumpStatLS(pw, p, Stats.RESOURCE_NAME_LOOKUP, "resourceNameLookup");
+ dumpStatLS(pw, p, Stats.GET_LAUNCHER_ACTIVITY, "getLauncherActivity");
+ dumpStatLS(pw, p, Stats.CHECK_LAUNCHER_ACTIVITY, "checkLauncherActivity");
}
for (int i = 0; i < mUsers.size(); i++) {
@@ -2774,7 +2886,9 @@
enforceShell();
- (new MyShellCommand()).exec(this, in, out, err, args, resultReceiver);
+ final int status = (new MyShellCommand()).exec(this, in, out, err, args, resultReceiver);
+
+ resultReceiver.send(status, null);
}
static class CommandException extends Exception {
@@ -2845,6 +2959,9 @@
case "clear-shortcuts":
handleClearShortcuts();
break;
+ case "verify-states": // hidden command to verify various internal states.
+ handleVerifyStates();
+ break;
default:
return handleDefaultCommands(cmd);
}
@@ -2987,7 +3104,16 @@
Slog.i(TAG, "cmd: handleClearShortcuts: " + mUserId + ", " + packageName);
- ShortcutService.this.cleanUpPackageForAllLoadedUsers(packageName, mUserId);
+ ShortcutService.this.cleanUpPackageForAllLoadedUsers(packageName, mUserId,
+ /* appStillExists = */ true);
+ }
+
+ private void handleVerifyStates() throws CommandException {
+ try {
+ verifyStatesForce(); // This will throw when there's an issue.
+ } catch (Throwable th) {
+ throw new CommandException(th.getMessage() + "\n" + Log.getStackTraceString(th));
+ }
}
}
@@ -3027,7 +3153,7 @@
}
final void wtf(String message) {
- wtf( message, /* exception= */ null);
+ wtf(message, /* exception= */ null);
}
// Injection point.
@@ -3073,8 +3199,8 @@
}
@VisibleForTesting
- int getMaxDynamicShortcutsForTest() {
- return mMaxDynamicShortcuts;
+ int getMaxShortcutsForTest() {
+ return mMaxShortcuts;
}
@VisibleForTesting
@@ -3141,6 +3267,10 @@
}
}
+ private final void verifyStatesForce() {
+ verifyStatesInner();
+ }
+
private void verifyStatesInner() {
synchronized (this) {
forEachLoadedUserLocked(u -> u.forAllPackageItems(ShortcutPackageItem::verifyStates));
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index f8ee325..7ea89c9 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -88,7 +88,7 @@
@Override
public String toString() {
- return String.format("{Package: %d, %s}", userId, packageName);
+ return String.format("[Package: %d, %s]", userId, packageName);
}
}
@@ -99,8 +99,6 @@
private final ArrayMap<String, ShortcutPackage> mPackages = new ArrayMap<>();
- private final SparseArray<ShortcutPackage> mPackagesFromUid = new SparseArray<>();
-
private final ArrayMap<PackageWithUser, ShortcutLauncher> mLaunchers = new ArrayMap<>();
/** Default launcher that can access the launcher apps APIs. */
@@ -244,12 +242,12 @@
}
}
- public void handlePackageAddedOrUpdated(@NonNull String packageName) {
+ public void handlePackageAddedOrUpdated(@NonNull String packageName, boolean forceRescan) {
final boolean isNewApp = !mPackages.containsKey(packageName);
final ShortcutPackage shortcutPackage = getPackageShortcuts(packageName);
- if (!shortcutPackage.handlePackageAddedOrUpdated(isNewApp)) {
+ if (!shortcutPackage.handlePackageAddedOrUpdated(isNewApp, forceRescan)) {
if (isNewApp) {
mPackages.remove(packageName);
}
@@ -381,8 +379,10 @@
pw.print(mUserId);
pw.print(" Known locale seq#: ");
pw.print(mKnownLocaleChangeSequenceNumber);
- pw.print(" Last app scan: ");
+ pw.print(" Last app scan: [");
pw.print(mLastAppScanTime);
+ pw.print("] ");
+ pw.print(ShortcutService.formatTime(mLastAppScanTime));
pw.println();
prefix += prefix + " ";
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 0bf0cac..627cdd0 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -737,9 +737,9 @@
long identity = Binder.clearCallingIdentity();
try {
if (enableQuietMode) {
+ ActivityManagerNative.getDefault().stopUser(userHandle, /* force */true, null);
LocalServices.getService(ActivityManagerInternal.class)
.killForegroundAppsForUser(userHandle);
- ActivityManagerNative.getDefault().stopUser(userHandle, /* force */true, null);
} else {
ActivityManagerNative.getDefault().startUserInBackground(userHandle);
}
@@ -1308,14 +1308,16 @@
}
if (mAppOpsService != null) { // We skip it until system-ready.
- final long token = Binder.clearCallingIdentity();
- try {
- mAppOpsService.setUserRestrictions(effective, mUserRestriconToken, userId);
- } catch (RemoteException e) {
- Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions");
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mAppOpsService.setUserRestrictions(effective, mUserRestriconToken, userId);
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions");
+ }
+ }
+ });
}
propagateUserRestrictionsLR(userId, effective, prevAppliedRestrictions);
@@ -2303,7 +2305,7 @@
*/
@Override
public UserInfo createRestrictedProfile(String name, int parentUserId) {
- checkManageUsersPermission("setupRestrictedProfile");
+ checkManageOrCreateUsersPermission("setupRestrictedProfile");
final UserInfo user = createProfileForUser(name, UserInfo.FLAG_RESTRICTED, parentUserId);
if (user == null) {
return null;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index f9f0fd9..22521b9 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -5718,14 +5718,15 @@
break;
}
- case KeyEvent.KEYCODE_FP_NAV_DOWN:
+ case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN:
// fall through
- case KeyEvent.KEYCODE_FP_NAV_UP:
+ case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP:
// fall through
- case KeyEvent.KEYCODE_FP_NAV_LEFT:
+ case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_LEFT:
// fall through
- case KeyEvent.KEYCODE_FP_NAV_RIGHT: {
- interceptStatusBarKey(event);
+ case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_RIGHT: {
+ result &= ~ACTION_PASS_TO_USER;
+ interceptSystemNavigationKey(event);
break;
}
@@ -5853,21 +5854,12 @@
* Handle statusbar expansion events.
* @param event
*/
- private void interceptStatusBarKey(KeyEvent event) {
- final int e = event.getKeyCode();
+ private void interceptSystemNavigationKey(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP && areSystemNavigationKeysEnabled()) {
- boolean doOpen = false;
- boolean doClose = false;
- doOpen = (e == KeyEvent.KEYCODE_FP_NAV_DOWN);
- doClose = (e == KeyEvent.KEYCODE_FP_NAV_UP);
IStatusBarService sbar = getStatusBarService();
if (sbar != null) {
try {
- if (doOpen) {
- sbar.expandNotificationsPanel();
- } else if (doClose) {
- sbar.collapsePanels();
- }
+ sbar.handleSystemNavigationKey(event.getKeyCode());
} catch (RemoteException e1) {
// oops, no statusbar. Ignore event.
}
@@ -7268,7 +7260,7 @@
private boolean areSystemNavigationKeysEnabled() {
return Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.SYSTEM_NAVIGATION_KEYS_ENABLED, 0) == 1;
+ Settings.Global.SYSTEM_NAVIGATION_KEYS_ENABLED, 1) == 1;
}
@Override
@@ -7670,6 +7662,34 @@
}
@Override
+ public boolean shouldRotateSeamlessly(int oldRotation, int newRotation) {
+ // For the upside down rotation we don't rotate seamlessly as the navigation
+ // bar moves position.
+ // Note most apps (using orientation:sensor or user as opposed to fullSensor)
+ // will not enter the reverse portrait orientation, so actually the
+ // orientation won't change at all.
+ if (oldRotation == mUpsideDownRotation || newRotation == mUpsideDownRotation) {
+ return false;
+ }
+ int delta = newRotation - oldRotation;
+ if (delta < 0) delta += 4;
+ // Likewise we don't rotate seamlessly for 180 degree rotations
+ // in this case the surfaces never resize, and our logic to
+ // revert the transformations on size change will fail. We could
+ // fix this in the future with the "tagged" frames idea.
+ if (delta == Surface.ROTATION_180) {
+ return false;
+ }
+
+ if (mTopFullscreenOpaqueWindowState != null && mTopIsFullscreen &&
+ mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation ==
+ ROTATION_ANIMATION_JUMPCUT) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
public void dump(String prefix, PrintWriter pw, String[] args) {
pw.print(prefix); pw.print("mSafeMode="); pw.print(mSafeMode);
pw.print(" mSystemReady="); pw.print(mSystemReady);
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 3ed6ec9..9ccfd67 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -18,12 +18,12 @@
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
+import android.app.RetailDemoModeServiceInternal;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
-import com.android.server.am.RetailDemoModeServiceInternal;
import android.app.ActivityManagerNative;
import android.content.BroadcastReceiver;
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index baa7f1e..ca92b90 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -31,6 +31,8 @@
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Slog;
+import android.view.KeyEvent;
+
import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
@@ -415,6 +417,18 @@
}
@Override
+ public void handleSystemNavigationKey(int key) throws RemoteException {
+ enforceExpandStatusBar();
+
+ if (mBar != null) {
+ try {
+ mBar.handleSystemNavigationKey(key);
+ } catch (RemoteException ex) {
+ }
+ }
+ }
+
+ @Override
public void disable(int what, IBinder token, String pkg) {
disableForUser(what, token, pkg, mCurrentUserId);
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index efd2382..7c2ba1e 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -906,10 +906,9 @@
public void onForegroundProfileSwitch(int newProfileId) {
// Ignore.
}
- });
+ }, TAG);
} catch (RemoteException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
+ e.rethrowAsRuntimeException();
}
}
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
index 361f0d4..bb76449 100644
--- a/services/core/java/com/android/server/webkit/SystemImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -270,5 +270,6 @@
// 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;
+ | PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING
+ | PackageManager.MATCH_UNINSTALLED_PACKAGES;
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index 9b971e0..846169c 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -63,6 +63,7 @@
mWebViewUpdatedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
switch (intent.getAction()) {
case Intent.ACTION_PACKAGE_REMOVED:
// When a package is replaced we will receive two intents, one
@@ -73,24 +74,22 @@
// run the update-logic twice.
if (intent.getExtras().getBoolean(Intent.EXTRA_REPLACING)) return;
mImpl.packageStateChanged(packageNameFromIntent(intent),
- PACKAGE_REMOVED);
+ PACKAGE_REMOVED, userId);
break;
case Intent.ACTION_PACKAGE_CHANGED:
// Ensure that we only heed PACKAGE_CHANGED intents if they change an
// entire package, not just a component
if (entirePackageChanged(intent)) {
mImpl.packageStateChanged(packageNameFromIntent(intent),
- PACKAGE_CHANGED);
+ PACKAGE_CHANGED, userId);
}
break;
case Intent.ACTION_PACKAGE_ADDED:
mImpl.packageStateChanged(packageNameFromIntent(intent),
(intent.getExtras().getBoolean(Intent.EXTRA_REPLACING)
- ? PACKAGE_ADDED_REPLACED : PACKAGE_ADDED));
+ ? PACKAGE_ADDED_REPLACED : PACKAGE_ADDED), userId);
break;
case Intent.ACTION_USER_ADDED:
- int userId =
- intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
mImpl.handleNewUser(userId);
break;
}
@@ -105,11 +104,14 @@
for (WebViewProviderInfo provider : mImpl.getWebViewPackages()) {
filter.addDataSchemeSpecificPart(provider.packageName, PatternMatcher.PATTERN_LITERAL);
}
- getContext().registerReceiver(mWebViewUpdatedReceiver, filter);
+
+ getContext().registerReceiverAsUser(mWebViewUpdatedReceiver, UserHandle.ALL, filter,
+ null /* broadcast permission */, null /* handler */);
IntentFilter userAddedFilter = new IntentFilter();
userAddedFilter.addAction(Intent.ACTION_USER_ADDED);
- getContext().registerReceiver(mWebViewUpdatedReceiver, userAddedFilter);
+ getContext().registerReceiverAsUser(mWebViewUpdatedReceiver, UserHandle.ALL,
+ userAddedFilter, null /* broadcast permission */, null /* handler */);
publishBinderService("webviewupdate", new BinderService(), true /*allowIsolated*/);
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
index ecab009..2cf1722 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
@@ -20,6 +20,7 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
+import android.os.UserHandle;
import android.util.Base64;
import android.util.Slog;
import android.webkit.WebViewFactory;
@@ -49,7 +50,10 @@
mWebViewUpdater = new WebViewUpdater(mContext, mSystemInterface);
}
- void packageStateChanged(String packageName, int changedState) {
+ void packageStateChanged(String packageName, int changedState, int userId) {
+ // We don't early out here in different cases where we could potentially early-out (e.g. if
+ // we receive PACKAGE_CHANGED for another user than the system user) since that would
+ // complicate this logic further and open up for more edge cases.
updateFallbackStateOnPackageChange(packageName, changedState);
mWebViewUpdater.packageStateChanged(packageName, changedState);
}
@@ -64,7 +68,7 @@
if (provider.availableByDefault && !provider.isFallback) {
try {
PackageInfo packageInfo = mSystemInterface.getPackageInfoForProvider(provider);
- if (isEnabledPackage(packageInfo)
+ if (isInstalledPackage(packageInfo) && isEnabledPackage(packageInfo)
&& mWebViewUpdater.isValidProvider(provider, packageInfo)) {
return true;
}
@@ -103,7 +107,7 @@
}
WebViewProviderInfo[] getValidWebViewPackages() {
- return mWebViewUpdater.getValidWebViewPackages();
+ return mWebViewUpdater.getValidAndInstalledWebViewPackages();
}
WebViewProviderInfo[] getWebViewPackages() {
@@ -254,6 +258,12 @@
// (not if it has been enabled/disabled).
return;
}
+ if (newPackage.packageName.equals(oldProviderName)
+ && (newPackage.lastUpdateTime
+ == mCurrentWebViewPackage.lastUpdateTime)) {
+ // If the chosen package hasn't been updated, then early-out
+ return;
+ }
}
// Only trigger update actions if the updated package is the one
// that will be used, or the one that was in use before the
@@ -373,14 +383,15 @@
}
}
- private ProviderAndPackageInfo[] getValidWebViewPackagesAndInfos() {
+ private ProviderAndPackageInfo[] getValidWebViewPackagesAndInfos(boolean onlyInstalled) {
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)) {
+ if ((!onlyInstalled || isInstalledPackage(packageInfo))
+ && isValidProvider(allProviders[n], packageInfo)) {
providers.add(new ProviderAndPackageInfo(allProviders[n], packageInfo));
}
} catch (NameNotFoundException e) {
@@ -393,8 +404,9 @@
/**
* Fetch only the currently valid WebView packages.
**/
- public WebViewProviderInfo[] getValidWebViewPackages() {
- ProviderAndPackageInfo[] providersAndPackageInfos = getValidWebViewPackagesAndInfos();
+ public WebViewProviderInfo[] getValidAndInstalledWebViewPackages() {
+ ProviderAndPackageInfo[] providersAndPackageInfos =
+ getValidWebViewPackagesAndInfos(true /* only fetch installed packages */);
WebViewProviderInfo[] providers =
new WebViewProviderInfo[providersAndPackageInfos.length];
for(int n = 0; n < providersAndPackageInfos.length; n++) {
@@ -421,29 +433,33 @@
*
*/
private PackageInfo findPreferredWebViewPackage() {
- ProviderAndPackageInfo[] providers = getValidWebViewPackagesAndInfos();
+ ProviderAndPackageInfo[] providers =
+ getValidWebViewPackagesAndInfos(false /* onlyInstalled */);
String userChosenProvider = mSystemInterface.getUserChosenWebViewProvider(mContext);
// If the user has chosen provider, use that
for (ProviderAndPackageInfo providerAndPackage : providers) {
if (providerAndPackage.provider.packageName.equals(userChosenProvider)
+ && isInstalledPackage(providerAndPackage.packageInfo)
&& 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).
+ // installed and enabled for the device owner, and available by default (not through
+ // user choice).
for (ProviderAndPackageInfo providerAndPackage : providers) {
if (providerAndPackage.provider.availableByDefault
+ && isInstalledPackage(providerAndPackage.packageInfo)
&& isEnabledPackage(providerAndPackage.packageInfo)) {
return providerAndPackage.packageInfo;
}
}
- // Could not find any enabled package either, use the most stable and default-available
- // provider.
+ // Could not find any installed and enabled package either, use the most stable and
+ // default-available provider.
for (ProviderAndPackageInfo providerAndPackage : providers) {
if (providerAndPackage.provider.availableByDefault) {
return providerAndPackage.packageInfo;
@@ -642,4 +658,13 @@
return packageInfo.applicationInfo.enabled;
}
+ /**
+ * Return true if the package is installed and not hidden
+ */
+ private static boolean isInstalledPackage(PackageInfo packageInfo) {
+ return (((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0)
+ && ((packageInfo.applicationInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_HIDDEN) == 0));
+ }
+
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index f57e83aa..b907da6 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -72,6 +72,7 @@
int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
boolean layoutConfigChanges;
boolean showForAllUsers;
+ int targetSdk;
// The input dispatching timeout for this application token in nanoseconds.
long inputDispatchingTimeoutNanos;
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index c4eca08..9d0fb61 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -28,6 +28,7 @@
import android.graphics.Matrix;
import android.graphics.Point;
import android.hardware.input.InputManager;
+import android.os.Build;
import android.os.IBinder;
import android.os.Message;
import android.os.Process;
@@ -289,7 +290,7 @@
if (!targetWin.isPotentialDragTarget()) {
return false;
}
- if ((mFlags & View.DRAG_FLAG_GLOBAL) == 0) {
+ if ((mFlags & View.DRAG_FLAG_GLOBAL) == 0 || !targetWindowSupportsGlobalDrag(targetWin)) {
// Drag is limited to the current window.
if (mLocalWin != targetWin.mClient.asBinder()) {
return false;
@@ -300,6 +301,13 @@
mSourceUserId == UserHandle.getUserId(targetWin.getOwningUid());
}
+ private boolean targetWindowSupportsGlobalDrag(WindowState targetWin) {
+ // Global drags are limited to system windows, and windows for apps that are targeting N and
+ // above.
+ return targetWin.mAppToken == null
+ || targetWin.mAppToken.targetSdk >= Build.VERSION_CODES.N;
+ }
+
/* helper - send a ACTION_DRAG_STARTED event only if the window has not
* previously been notified, i.e. it became visible after the drag operation
* was begun. This is a rare case.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8474fcf..54960a4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -41,8 +41,10 @@
import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
+import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.Region;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerInternal;
@@ -291,6 +293,9 @@
/** Amount of time (in milliseconds) to delay before declaring a window freeze timeout. */
static final int WINDOW_FREEZE_TIMEOUT_DURATION = 2000;
+ /** Amount of time (in milliseconds) to delay before declaring a seamless rotation timeout. */
+ static final int SEAMLESS_ROTATION_TIMEOUT_DURATION = 2000;
+
/** Amount of time (in milliseconds) to delay before declaring a window replacement timeout. */
static final int WINDOW_REPLACEMENT_TIMEOUT_DURATION = 2000;
@@ -516,6 +521,9 @@
final Rect mTmpRect = new Rect();
final Rect mTmpRect2 = new Rect();
final Rect mTmpRect3 = new Rect();
+ final RectF mTmpRectF = new RectF();
+
+ final Matrix mTmpTransform = new Matrix();
boolean mDisplayReady;
boolean mSafeMode;
@@ -2995,7 +3003,8 @@
if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
}
- if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
+ if (win.isWinVisibleLw() && !winAnimator.isAnimationSet()
+ && winAnimator.applyAnimationLocked(transit, false)) {
focusMayChange = isDefaultDisplay;
win.mAnimatingExit = true;
win.mWinAnimator.mAnimating = true;
@@ -3420,7 +3429,7 @@
int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId,
int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
Rect taskBounds, Configuration config, int taskResizeMode, boolean alwaysFocusable,
- boolean homeTask) {
+ boolean homeTask, int targetSdkVersion) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"addAppToken()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3450,6 +3459,7 @@
atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
atoken.appFullscreen = fullscreen;
atoken.showForAllUsers = showForAllUsers;
+ atoken.targetSdk = targetSdkVersion;
atoken.requestedOrientation = requestedOrientation;
atoken.layoutConfigChanges = (configChanges &
(ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;
@@ -6566,6 +6576,7 @@
Binder.restoreCallingIdentity(origId);
}
+
// TODO(multidisplay): Rotate any display?
/**
* Updates the current rotation.
@@ -6625,6 +6636,8 @@
+ ", forceApp=" + mForcedAppOrientation);
}
+ int oldRotation = mRotation;
+
mRotation = rotation;
mAltOrientation = altOrientation;
mPolicy.setRotationLw(mRotation);
@@ -6641,10 +6654,32 @@
} else {
mPolicy.selectRotationAnimationLw(anim);
}
- startFreezingDisplayLocked(inTransaction, anim[0], anim[1]);
- // startFreezingDisplayLocked can reset the ScreenRotationAnimation.
- screenRotationAnimation =
+ boolean rotateSeamlessly = mPolicy.shouldRotateSeamlessly(oldRotation, mRotation);
+ final WindowList windows = displayContent.getWindowList();
+ // We can't rotate seamlessly while an existing seamless rotation is still
+ // waiting on windows to finish drawing.
+ if (rotateSeamlessly) {
+ for (int i = windows.size() - 1; i >= 0; i--) {
+ WindowState w = windows.get(i);
+ if (w.mSeamlesslyRotated) {
+ rotateSeamlessly = false;
+ break;
+ }
+ }
+ }
+
+ if (!rotateSeamlessly) {
+ startFreezingDisplayLocked(inTransaction, anim[0], anim[1]);
+ // startFreezingDisplayLocked can reset the ScreenRotationAnimation.
+ screenRotationAnimation =
mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
+ } else {
+ // The screen rotation animation uses a screenshot to freeze the screen
+ // while windows resize underneath.
+ // When we are rotating seamlessly, we allow the elements to transition
+ // to their rotated state independently and without a freeze required.
+ screenRotationAnimation = null;
+ }
// We need to update our screen size information to match the new rotation. If the rotation
// has actually changed then this method will return true and, according to the comment at
@@ -6673,6 +6708,13 @@
}
}
+ if (rotateSeamlessly) {
+ for (int i = windows.size() - 1; i >= 0; i--) {
+ WindowState w = windows.get(i);
+ w.mWinAnimator.seamlesslyRotateWindow(oldRotation, mRotation);
+ }
+ }
+
mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
} finally {
if (!inTransaction) {
@@ -6683,19 +6725,22 @@
}
}
- final WindowList windows = displayContent.getWindowList();
for (int i = windows.size() - 1; i >= 0; i--) {
WindowState w = windows.get(i);
// Discard surface after orientation change, these can't be reused.
if (w.mAppToken != null) {
w.mAppToken.destroySavedSurfaces();
}
- if (w.mHasSurface) {
+ if (w.mHasSurface && !rotateSeamlessly) {
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Set mOrientationChanging of " + w);
w.mOrientationChanging = true;
mWindowPlacerLocked.mOrientationChangeComplete = false;
+ w.mLastFreezeDuration = 0;
}
- w.mLastFreezeDuration = 0;
+ }
+ if (rotateSeamlessly) {
+ mH.removeMessages(H.SEAMLESS_ROTATION_TIMEOUT);
+ mH.sendEmptyMessageDelayed(H.SEAMLESS_ROTATION_TIMEOUT, SEAMLESS_ROTATION_TIMEOUT_DURATION);
}
for (int i=mRotationWatchers.size()-1; i>=0; i--) {
@@ -6705,7 +6750,7 @@
}
}
- //TODO (multidisplay): Magnification is supported only for the default display.
+ // TODO (multidisplay): Magnification is supported only for the default display.
// Announce rotation only if we will not animate as we already have the
// windows in final state. Otherwise, we make this call at the rotation end.
if (screenRotationAnimation == null && mAccessibilityController != null
@@ -7993,8 +8038,8 @@
public static final int NOTIFY_STARTING_WINDOW_DRAWN = 50;
public static final int UPDATE_ANIMATION_SCALE = 51;
public static final int WINDOW_REMOVE_TIMEOUT = 52;
-
public static final int NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED = 53;
+ public static final int SEAMLESS_ROTATION_TIMEOUT = 54;
/**
* Used to denote that an integer field in a message will not be used.
@@ -8634,6 +8679,25 @@
mAmInternal.notifyDockedStackMinimizedChanged(msg.arg1 == 1);
}
break;
+ case SEAMLESS_ROTATION_TIMEOUT: {
+ // Rotation only supported on primary display.
+ // TODO(multi-display)
+ final DisplayContent displayContent = getDefaultDisplayContentLocked();
+ final WindowList windows = displayContent.getWindowList();
+ boolean layoutNeeded = false;
+ for (int i = windows.size() - 1; i >= 0; i--) {
+ WindowState w = windows.get(i);
+ if (w.mSeamlesslyRotated) {
+ layoutNeeded = true;
+ w.setDisplayLayoutNeeded();
+ }
+ w.mSeamlesslyRotated = false;
+ }
+ if (layoutNeeded) {
+ mWindowPlacerLocked.performSurfacePlacement();
+ }
+ }
+ break;
}
if (DEBUG_WINDOW_TRACE) {
Slog.v(TAG_WM, "handleMessage: exit");
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 08bfa2d..99fec7bd 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -494,6 +494,15 @@
/** @see #isResizedWhileNotDragResizingReported(). */
private boolean mResizedWhileNotDragResizingReported;
+ /**
+ * During seamless rotation we have two phases, first the old window contents
+ * are rotated to look as if they didn't move in the new coordinate system. Then we
+ * have to freeze updates to this layer (to preserve the transformation) until
+ * the resize actually occurs. This is true from when the transformation is set
+ * and false until the transaction to resize is sent.
+ */
+ boolean mSeamlesslyRotated = false;
+
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
int viewVisibility, final DisplayContent displayContent) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 36d9697..6c55495 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -51,12 +51,14 @@
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.Region;
import android.os.Debug;
import android.os.RemoteException;
import android.util.Slog;
import android.view.DisplayInfo;
import android.view.MagnificationSpec;
+import android.view.Surface;
import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceControl;
import android.view.WindowManager;
@@ -1400,6 +1402,9 @@
mExtraHScale = (float) 1.0;
mExtraVScale = (float) 1.0;
+ boolean wasForceScaled = mForceScaleUntilResize;
+ boolean wasSeamlesslyRotated = w.mSeamlesslyRotated;
+
// Once relayout has been called at least once, we need to make sure
// we only resize the client surface during calls to relayout. For
// clients which use indeterminate measure specs (MATCH_PARENT),
@@ -1407,21 +1412,17 @@
// However, this would be unsafe, as the client may be in the middle
// of producing a frame at the old size, having just completed layout
// to find the surface size changed underneath it.
- //
- // TODO: For N we only apply this fix to the pinned workspace. As we
- // aren't observing known issues here outside of PiP resizing. (Typically
- // the other windows that use -1 are PopupWindows which aren't likely
- // to be rendering while we resize).
-
- boolean wasForceScaled = mForceScaleUntilResize;
-
- if (!w.inPinnedWorkspace() || (!w.mRelayoutCalled || w.mInRelayout)) {
+ if (!w.mRelayoutCalled || w.mInRelayout) {
mSurfaceResized = mSurfaceController.setSizeInTransaction(
mTmpSize.width(), mTmpSize.height(), recoveringMemory);
} else {
mSurfaceResized = false;
}
mForceScaleUntilResize = mForceScaleUntilResize && !mSurfaceResized;
+ // If we are undergoing seamless rotation, the surface has already
+ // been set up to persist at it's old location. We need to freeze
+ // updates until a resize occurs.
+ w.mSeamlesslyRotated = w.mSeamlesslyRotated && !mSurfaceResized;
calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect);
@@ -1471,17 +1472,20 @@
// will be seamless.
mForceScaleUntilResize = true;
} else {
- mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top,
- recoveringMemory);
+ if (!w.mSeamlesslyRotated) {
+ mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top,
+ recoveringMemory);
+ }
}
// If we are ending the scaling mode. We switch to SCALING_MODE_FREEZE
- // to prevent further updates until buffer latch. Normally position
- // would continue to apply immediately. But we need a different position
- // before and after resize (since we have scaled the shadows, as discussed
- // above).
- if (wasForceScaled && !mForceScaleUntilResize) {
- mSurfaceController.setPositionAppliesWithResizeInTransaction(true);
+ // to prevent further updates until buffer latch.
+ // When ending both force scaling, and seamless rotation, we need to freeze
+ // the Surface geometry until a buffer comes in at the new size (normally position and crop
+ // are unfrozen). setGeometryAppliesWithResizeInTransaction accomplishes this for us.
+ if ((wasForceScaled && !mForceScaleUntilResize) ||
+ (wasSeamlesslyRotated && !w.mSeamlesslyRotated)) {
+ mSurfaceController.setGeometryAppliesWithResizeInTransaction(true);
mSurfaceController.forceScaleableInTransaction(false);
}
@@ -1493,12 +1497,13 @@
-w.mAttrs.surfaceInsets.right, -w.mAttrs.surfaceInsets.bottom);
}
- updateSurfaceWindowCrop(clipRect, mTmpFinalClipRect, recoveringMemory);
-
- mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * mExtraHScale,
- mDtDx * w.mVScale * mExtraVScale,
- mDsDy * w.mHScale * mExtraHScale,
- mDtDy * w.mVScale * mExtraVScale, recoveringMemory);
+ if (!w.mSeamlesslyRotated) {
+ updateSurfaceWindowCrop(clipRect, mTmpFinalClipRect, recoveringMemory);
+ mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * mExtraHScale,
+ mDtDx * w.mVScale * mExtraVScale,
+ mDsDy * w.mHScale * mExtraHScale,
+ mDtDy * w.mVScale * mExtraVScale, recoveringMemory);
+ }
if (mSurfaceResized) {
mReportSurfaceResized = true;
@@ -2084,4 +2089,98 @@
void endDelayingAnimationStart() {
mAnimationStartDelayed = false;
}
+
+ void seamlesslyRotateWindow(int oldRotation, int newRotation) {
+ final WindowState w = mWin;
+ if (!w.isVisibleNow() || w.mIsWallpaper) {
+ return;
+ }
+
+ final Rect cropRect = mService.mTmpRect;
+ final Rect displayRect = mService.mTmpRect2;
+ final RectF frameRect = mService.mTmpRectF;
+ final Matrix transform = mService.mTmpTransform;
+
+ final float x = w.mFrame.left;
+ final float y = w.mFrame.top;
+ final float width = w.mFrame.width();
+ final float height = w.mFrame.height();
+
+ mService.getDefaultDisplayContentLocked().getLogicalDisplayRect(displayRect);
+ final float displayWidth = displayRect.width();
+ final float displayHeight = displayRect.height();
+
+ // Compute a transform matrix to undo the coordinate space transformation,
+ // and present the window at the same physical position it previously occupied.
+ final int deltaRotation = DisplayContent.deltaRotation(newRotation, oldRotation);
+ switch (deltaRotation) {
+ case Surface.ROTATION_0:
+ transform.reset();
+ break;
+ case Surface.ROTATION_270:
+ transform.setRotate(270, 0, 0);
+ transform.postTranslate(0, displayHeight);
+ transform.postTranslate(y, 0);
+ break;
+ case Surface.ROTATION_180:
+ transform.reset();
+ break;
+ case Surface.ROTATION_90:
+ transform.setRotate(90, 0, 0);
+ transform.postTranslate(displayWidth, 0);
+ transform.postTranslate(-y, x);
+ break;
+ }
+
+ // We have two cases:
+ // 1. Windows with NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY:
+ // These windows never change buffer size when rotating. Rather the window manager
+ // just updates the scaling factors to fit in the new coordinate system,
+ // and SurfaceFlinger takes care of updating the buffer contents. So in this case
+ // we just need we just need to update the scaling factors and things are seamless
+ // already.
+ // 2. Other windows:
+ // In this case, we need to apply a rotation matrix to the window. For example
+ // if we have a portrait window and rotate to landscape, the window is still portrait
+ // and now extends off the bottom of the screen (and only halfway across). Essentially we
+ // apply a transform to display the current buffer at it's old position
+ // (in the new coordinate space). We then freeze layer updates until the resize
+ // occurs, at which point we undo, them.
+ if (w.isChildWindow() && mSurfaceController.getTransformToDisplayInverse()) {
+ frameRect.set(x, y, x+width, y+height);
+ transform.mapRect(frameRect);
+
+ w.mAttrs.x = (int) frameRect.left - w.mAttachedWindow.mFrame.left;
+ w.mAttrs.y = (int) frameRect.top - w.mAttachedWindow.mFrame.top;
+ w.mAttrs.width = (int) Math.ceil(frameRect.width());
+ w.mAttrs.height = (int) Math.ceil(frameRect.height());
+
+ w.setWindowScale(w.mRequestedWidth, w.mRequestedHeight);
+
+ w.applyGravityAndUpdateFrame(w.mContainingFrame, w.mDisplayFrame);
+ computeShownFrameLocked();
+ setSurfaceBoundariesLocked(false);
+
+ // The stack bounds will not yet be rotated at this point so setSurfaceBoundaries locked
+ // will crop us incorrectly. Overwrite the crop, exposing the full surface. By the next
+ // transaction this will be corrected.
+ cropRect.set(0, 0, w.mRequestedWidth, w.mRequestedWidth + w.mRequestedHeight);
+ mSurfaceController.setCropInTransaction(cropRect, false);
+ } else {
+ w.mSeamlesslyRotated = true;
+ transform.getValues(mService.mTmpFloats);
+
+ float DsDx = mService.mTmpFloats[Matrix.MSCALE_X];
+ float DtDx = mService.mTmpFloats[Matrix.MSKEW_Y];
+ float DsDy = mService.mTmpFloats[Matrix.MSKEW_X];
+ float DtDy = mService.mTmpFloats[Matrix.MSCALE_Y];
+ float nx = mService.mTmpFloats[Matrix.MTRANS_X];
+ float ny = mService.mTmpFloats[Matrix.MTRANS_Y];
+ mSurfaceController.setPositionInTransaction(nx, ny, false);
+ mSurfaceController.setMatrixInTransaction(DsDx * w.mHScale,
+ DtDx * w.mVScale,
+ DsDy * w.mHScale,
+ DtDy * w.mVScale, false);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index fd0bb99..3121415 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -259,8 +259,8 @@
}
}
- void setPositionAppliesWithResizeInTransaction(boolean recoveringMemory) {
- mSurfaceControl.setPositionAppliesWithResize();
+ void setGeometryAppliesWithResizeInTransaction(boolean recoveringMemory) {
+ mSurfaceControl.setGeometryAppliesWithResize();
}
void setMatrixInTransaction(float dsdx, float dtdx, float dsdy, float dtdy,
@@ -457,6 +457,10 @@
return mSurfaceControl.getHandle();
}
+ boolean getTransformToDisplayInverse() {
+ return mSurfaceControl.getTransformToDisplayInverse();
+ }
+
void getSurface(Surface outSurface) {
outSurface.copyFrom(mSurfaceControl);
}
@@ -581,10 +585,10 @@
}
@Override
- public void setPositionAppliesWithResize() {
- if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setPositionAppliesWithResize(): OLD: "
- + this + ". Called by" + Debug.getCallers(9));
- super.setPositionAppliesWithResize();
+ public void setGeometryAppliesWithResize() {
+ if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setGeometryAppliesWithResize(): OLD: "
+ + this + ". Called by" + Debug.getCallers(3));
+ super.setGeometryAppliesWithResize();
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 4148cd0..359063c 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -731,9 +731,7 @@
}
try {
- if (task == null || task.mStack.getBoundsAnimating()) {
- w.mClient.moved(left, top);
- }
+ w.mClient.moved(left, top);
} catch (RemoteException e) {
}
w.mMovedByResize = false;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 8f8ba1d..76424d8 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -57,7 +57,6 @@
import com.android.internal.widget.ILockSettings;
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.am.ActivityManagerService;
-import com.android.server.am.RetailDemoModeService;
import com.android.server.audio.AudioService;
import com.android.server.camera.CameraService;
import com.android.server.clipboard.ClipboardService;
@@ -88,6 +87,7 @@
import com.android.server.power.PowerManagerService;
import com.android.server.power.ShutdownThread;
import com.android.server.restrictions.RestrictionsManagerService;
+import com.android.server.retaildemo.RetailDemoModeService;
import com.android.server.soundtrigger.SoundTriggerService;
import com.android.server.statusbar.StatusBarManagerService;
import com.android.server.storage.DeviceStorageMonitorService;
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 485f2f5..ce37426 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -367,8 +367,9 @@
}
// Note that this parses RA and may throw IllegalArgumentException (from
- // Buffer.position(int) ) or IndexOutOfBoundsException (from ByteBuffer.get(int) ) if
- // parsing encounters something non-compliant with specifications.
+ // Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException
+ // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with
+ // specifications.
Ra(byte[] packet, int length) {
mPacket = ByteBuffer.allocate(length).put(ByteBuffer.wrap(packet, 0, length));
mPacket.clear();
@@ -418,6 +419,10 @@
// compatibility.
break;
}
+ if (optionLength <= 0) {
+ throw new IllegalArgumentException(String.format(
+ "Invalid option length opt=%d len=%d", optionType, optionLength));
+ }
mPacket.position(mPacket.position() + optionLength);
}
// Mark non-lifetime bytes since last lifetime.
diff --git a/services/retaildemo/Android.mk b/services/retaildemo/Android.mk
new file mode 100644
index 0000000..670c6bf
--- /dev/null
+++ b/services/retaildemo/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.retaildemo
+
+LOCAL_SRC_FILES += \
+ $(call all-java-files-under,java)
+
+LOCAL_JAVA_LIBRARIES := services.core
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/core/java/com/android/server/am/RetailDemoModeService.java b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
similarity index 70%
rename from services/core/java/com/android/server/am/RetailDemoModeService.java
rename to services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
index 6a5ec96..96e6da74 100644
--- a/services/core/java/com/android/server/am/RetailDemoModeService.java
+++ b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
@@ -14,23 +14,32 @@
* limitations under the License
*/
-package com.android.server.am;
+package com.android.server.retaildemo;
+import android.app.ActivityManagerInternal;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.app.RetailDemoModeServiceInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.content.res.Configuration;
import android.database.ContentObserver;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraManager;
+import android.media.AudioManager;
+import android.media.AudioSystem;
import android.net.Uri;
import android.os.Environment;
import android.os.FileUtils;
@@ -44,13 +53,17 @@
import android.os.UserManager;
import android.provider.Settings;
import android.util.Slog;
-
import com.android.internal.os.BackgroundThread;
import com.android.internal.R;
import com.android.internal.widget.LockPatternUtils;
+import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
+import com.android.server.am.ActivityManagerService;
+import com.android.server.retaildemo.UserInactivityCountdownDialog.OnCountDownExpiredListener;
+
import java.io.File;
+import java.util.ArrayList;
public class RetailDemoModeService extends SystemService {
private static final boolean DEBUG = false;
@@ -65,9 +78,19 @@
private static final long SCREEN_WAKEUP_DELAY = 2500;
private static final long USER_INACTIVITY_TIMEOUT = 30000;
+ private static final long WARNING_DIALOG_TIMEOUT = 6000;
+ private static final long MILLIS_PER_SECOND = 1000;
+
+ private static final int[] VOLUME_STREAMS_TO_MUTE = {
+ AudioSystem.STREAM_RING,
+ AudioSystem.STREAM_MUSIC
+ };
boolean mDeviceInDemoMode = false;
+ int mCurrentUserId;
private ActivityManagerService mAms;
+ private ActivityManagerInternal mAmi;
+ private AudioManager mAudioManager;
private NotificationManager mNm;
private UserManager mUm;
private PowerManager mPm;
@@ -75,6 +98,9 @@
Handler mHandler;
private ServiceThread mHandlerThread;
private PendingIntent mResetDemoPendingIntent;
+ private CameraManager mCameraManager;
+ private String[] mCameraIdsWithFlash;
+ private Configuration mPrimaryUserConfiguration;
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -110,20 +136,20 @@
mWakeLock.acquire();
break;
case MSG_INACTIVITY_TIME_OUT:
- IPackageManager pm = AppGlobals.getPackageManager();
+ final IPackageManager pm = AppGlobals.getPackageManager();
int enabledState = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
String demoLauncherComponent = getContext().getResources()
.getString(R.string.config_demoModeLauncherComponent);
try {
enabledState = pm.getComponentEnabledSetting(
ComponentName.unflattenFromString(demoLauncherComponent),
- getActivityManager().getCurrentUser().id);
+ mCurrentUserId);
} catch (RemoteException exc) {
- // XXX: shouldn't happen
+ Slog.e(TAG, "Unable to talk to Package Manager", exc);
}
if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
- Slog.i(TAG, "Restarting session due to user inactivity timeout");
- sendEmptyMessage(MSG_START_NEW_SESSION);
+ Slog.i(TAG, "User inactivity timeout reached");
+ showInactivityCountdownDialog();
}
break;
case MSG_START_NEW_SESSION:
@@ -131,7 +157,8 @@
Slog.d(TAG, "Switching to a new demo user");
}
removeMessages(MSG_START_NEW_SESSION);
- UserInfo demoUser = getUserManager().createUser(DEMO_USER_NAME,
+ removeMessages(MSG_INACTIVITY_TIME_OUT);
+ final UserInfo demoUser = getUserManager().createUser(DEMO_USER_NAME,
UserInfo.FLAG_DEMO | UserInfo.FLAG_EPHEMERAL);
if (demoUser != null) {
setupDemoUser(demoUser);
@@ -142,6 +169,25 @@
}
}
+ private void showInactivityCountdownDialog() {
+ UserInactivityCountdownDialog dialog = new UserInactivityCountdownDialog(getContext(),
+ WARNING_DIALOG_TIMEOUT, MILLIS_PER_SECOND);
+ dialog.setPositiveButtonClickListener(null);
+ dialog.setNegativeButtonClickListener(new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ mHandler.sendEmptyMessage(MSG_START_NEW_SESSION);
+ }
+ });
+ dialog.setOnCountDownExpiredListener(new OnCountDownExpiredListener() {
+ @Override
+ public void onCountDownExpired() {
+ mHandler.sendEmptyMessage(MSG_START_NEW_SESSION);
+ }
+ });
+ dialog.show();
+ }
+
public RetailDemoModeService(Context context) {
super(context);
}
@@ -167,7 +213,7 @@
return mResetDemoPendingIntent;
}
- void setupDemoUser(UserInfo userInfo) {
+ private void setupDemoUser(UserInfo userInfo) {
UserManager um = getUserManager();
UserHandle user = UserHandle.of(userInfo.id);
LockPatternUtils lockPatternUtils = new LockPatternUtils(getContext());
@@ -194,6 +240,13 @@
return mUm;
}
+ private AudioManager getAudioManager() {
+ if (mAudioManager == null) {
+ mAudioManager = getContext().getSystemService(AudioManager.class);
+ }
+ return mAudioManager;
+ }
+
private void registerSettingsChangeObserver() {
final Uri deviceDemoModeUri = Settings.Global.getUriFor(Settings.Global.DEVICE_DEMO_MODE);
final Uri deviceProvisionedUri = Settings.Global.getUriFor(
@@ -230,13 +283,13 @@
UserHandle.USER_SYSTEM);
}
- boolean isDeviceProvisioned() {
+ private boolean isDeviceProvisioned() {
return Settings.Global.getInt(
getContext().getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0;
}
private boolean deleteDemoFolderContents() {
- File dir = Environment.getDataPreloadsDemoDirectory();
+ final File dir = Environment.getDataPreloadsDemoDirectory();
Slog.i(TAG, "Deleting contents of " + dir);
return FileUtils.deleteContents(dir);
}
@@ -248,6 +301,46 @@
getContext().registerReceiver(mBroadcastReceiver, filter);
}
+ private String[] getCameraIdsWithFlash() {
+ ArrayList<String> cameraIdsList = new ArrayList<String>();
+ try {
+ for (String cameraId : mCameraManager.getCameraIdList()) {
+ CameraCharacteristics c = mCameraManager.getCameraCharacteristics(cameraId);
+ if (Boolean.TRUE.equals(c.get(CameraCharacteristics.FLASH_INFO_AVAILABLE))) {
+ cameraIdsList.add(cameraId);
+ }
+ }
+ } catch (CameraAccessException e) {
+ Slog.e(TAG, "Unable to access camera while getting camera id list", e);
+ }
+ return cameraIdsList.toArray(new String[cameraIdsList.size()]);
+ }
+
+ private void turnOffAllFlashLights() {
+ for (String cameraId : mCameraIdsWithFlash) {
+ try {
+ mCameraManager.setTorchMode(cameraId, false);
+ } catch (CameraAccessException e) {
+ Slog.e(TAG, "Unable to access camera " + cameraId + " while turning off flash", e);
+ }
+ }
+ }
+
+ private void muteVolumeStreams() {
+ for (int stream : VOLUME_STREAMS_TO_MUTE) {
+ getAudioManager().setStreamVolume(stream, getAudioManager().getStreamMinVolume(stream),
+ 0);
+ }
+ }
+
+ private Configuration getPrimaryUsersConfiguration() {
+ if (mPrimaryUserConfiguration == null) {
+ Settings.System.getConfiguration(getContext().getContentResolver(),
+ mPrimaryUserConfiguration = new Configuration());
+ }
+ return mPrimaryUserConfiguration;
+ }
+
@Override
public void onStart() {
if (DEBUG) {
@@ -266,9 +359,12 @@
return;
}
mPm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
+ mAmi = LocalServices.getService(ActivityManagerInternal.class);
mWakeLock = mPm
.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, TAG);
mNm = NotificationManager.from(getContext());
+ mCameraManager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
+ mCameraIdsWithFlash = getCameraIdsWithFlash();
if (UserManager.isDeviceInDemoMode(getContext())) {
mDeviceInDemoMode = true;
@@ -286,7 +382,7 @@
if (DEBUG) {
Slog.d(TAG, "onSwitchUser: " + userId);
}
- UserInfo ui = getUserManager().getUserInfo(userId);
+ final UserInfo ui = getUserManager().getUserInfo(userId);
if (!ui.isDemo()) {
Slog.wtf(TAG, "Should not allow switch to non-demo user in demo mode");
return;
@@ -294,10 +390,14 @@
if (!mWakeLock.isHeld()) {
mWakeLock.acquire();
}
+ mCurrentUserId = userId;
mNm.notifyAsUser(TAG, 1, createResetNotification(), UserHandle.of(userId));
+ turnOffAllFlashLights();
+ muteVolumeStreams();
+ mAmi.updatePersistentConfigurationForUser(getPrimaryUsersConfiguration(), userId);
}
- public RetailDemoModeServiceInternal mLocalService = new RetailDemoModeServiceInternal() {
+ private RetailDemoModeServiceInternal mLocalService = new RetailDemoModeServiceInternal() {
private static final long USER_ACTIVITY_DEBOUNCE_TIME = 2000;
private long mLastUserActivityTime = 0;
diff --git a/services/retaildemo/java/com/android/server/retaildemo/UserInactivityCountdownDialog.java b/services/retaildemo/java/com/android/server/retaildemo/UserInactivityCountdownDialog.java
new file mode 100644
index 0000000..e6548b7
--- /dev/null
+++ b/services/retaildemo/java/com/android/server/retaildemo/UserInactivityCountdownDialog.java
@@ -0,0 +1,109 @@
+/*
+ * 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.retaildemo;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.os.CountDownTimer;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+import com.android.internal.R;
+
+public class UserInactivityCountdownDialog extends AlertDialog {
+
+ private OnCountDownExpiredListener mOnCountDownExpiredListener;
+ private View mDialogView;
+ private CountDownTimer mCountDownTimer;
+ private long mCountDownDuration;
+ private long mRefreshInterval;
+
+ UserInactivityCountdownDialog(Context context, long duration, long refreshInterval) {
+ super(context);
+
+ mCountDownDuration = duration;
+ mRefreshInterval = refreshInterval;
+ mDialogView = LayoutInflater.from(context).inflate(R.layout.alert_dialog, null);
+ String msg = context.getString(R.string.demo_user_inactivity_timeout_countdown, duration);
+ getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ WindowManager.LayoutParams attrs = getWindow().getAttributes();
+ attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+ getWindow().setAttributes(attrs);
+ setTitle(R.string.demo_user_inactivity_timeout_title);
+ setView(mDialogView);
+ setMessage(msg);
+ }
+
+ public void setOnCountDownExpiredListener(
+ OnCountDownExpiredListener onCountDownExpiredListener) {
+ mOnCountDownExpiredListener = onCountDownExpiredListener;
+ }
+
+ public void setPositiveButtonClickListener(OnClickListener onClickListener) {
+ setButton(Dialog.BUTTON_POSITIVE,
+ getContext().getString(R.string.demo_user_inactivity_timeout_left_button),
+ onClickListener);
+ }
+
+ public void setNegativeButtonClickListener(OnClickListener onClickListener) {
+ setButton(Dialog.BUTTON_NEGATIVE,
+ getContext().getString(R.string.demo_user_inactivity_timeout_right_button),
+ onClickListener);
+ }
+
+ @Override
+ public void show() {
+ super.show();
+ mDialogView.post(new Runnable() {
+ @Override
+ public void run() {
+ mCountDownTimer = new CountDownTimer(mCountDownDuration, mRefreshInterval) {
+
+ @Override
+ public void onTick(long millisUntilFinished) {
+ String msg = getContext().getResources().getString(
+ R.string.demo_user_inactivity_timeout_countdown,
+ millisUntilFinished / 1000);
+ ((TextView) mDialogView.findViewById(R.id.message)).setText(msg);
+ }
+
+ @Override
+ public void onFinish() {
+ dismiss();
+ if (mOnCountDownExpiredListener != null)
+ mOnCountDownExpiredListener.onCountDownExpired();
+ }
+ }.start();
+ }
+ });
+ }
+
+ @Override
+ public void dismiss() {
+ super.dismiss();
+ if (mCountDownTimer != null) {
+ mCountDownTimer.cancel();
+ }
+ }
+
+ interface OnCountDownExpiredListener {
+ void onCountDownExpired();
+ }
+}
diff --git a/services/tests/servicestests/res/drawable/icon3.png b/services/tests/servicestests/res/drawable/icon3.png
new file mode 100644
index 0000000..64eb294
--- /dev/null
+++ b/services/tests/servicestests/res/drawable/icon3.png
Binary files differ
diff --git a/services/tests/servicestests/res/xml/shortcut_1.xml b/services/tests/servicestests/res/xml/shortcut_1.xml
index f6d54fc..e3f9172 100644
--- a/services/tests/servicestests/res/xml/shortcut_1.xml
+++ b/services/tests/servicestests/res/xml/shortcut_1.xml
@@ -2,12 +2,17 @@
<shortcut
android:shortcutId="ms1"
android:enabled="true"
- android:shortcutIcon="@drawable/icon1"
+ android:icon="@drawable/icon1"
android:shortcutShortLabel="@string/shortcut_title1"
android:shortcutLongLabel="@string/shortcut_text1"
android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
- android:shortcutCategories="android.shortcut.conversation:android.shortcut.media"
- android:shortcutIntentAction="action1"
- android:shortcutIntentData="data1"
- />
+ >
+ <intent
+ android:action="action1"
+ android:data="data1"
+ >
+ </intent>
+ <categories android:name="android.shortcut.conversation" />
+ <categories android:name="android.shortcut.media" />
+ </shortcut>
</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_1_alt.xml b/services/tests/servicestests/res/xml/shortcut_1_alt.xml
index bf14f49..2d5e8e7 100644
--- a/services/tests/servicestests/res/xml/shortcut_1_alt.xml
+++ b/services/tests/servicestests/res/xml/shortcut_1_alt.xml
@@ -17,12 +17,17 @@
<shortcut
android:shortcutId="ms1-alt"
android:enabled="true"
- android:shortcutIcon="@drawable/icon1"
+ android:icon="@drawable/icon1"
android:shortcutShortLabel="@string/shortcut_title1"
android:shortcutLongLabel="@string/shortcut_text1"
android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
- android:shortcutCategories="android.shortcut.conversation:android.shortcut.media"
- android:shortcutIntentAction="action1"
- android:shortcutIntentData="data1"
- />
+ >
+ <intent
+ android:action="action1"
+ android:data="data1"
+ >
+ </intent>
+ <categories android:name="android.shortcut.conversation" />
+ <categories android:name="android.shortcut.media" />
+ </shortcut>
</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_1_disable.xml b/services/tests/servicestests/res/xml/shortcut_1_disable.xml
index 81a84b4..e3ee3a0 100644
--- a/services/tests/servicestests/res/xml/shortcut_1_disable.xml
+++ b/services/tests/servicestests/res/xml/shortcut_1_disable.xml
@@ -17,7 +17,7 @@
<shortcut
android:shortcutId="ms1"
android:enabled="false"
- android:shortcutIcon="@drawable/icon2"
+ android:icon="@drawable/icon2"
android:shortcutShortLabel="@string/shortcut_title2"
android:shortcutLongLabel="@string/shortcut_text2"
android:shortcutDisabledMessage="@string/shortcut_disabled_message2"
diff --git a/services/tests/servicestests/res/xml/shortcut_2.xml b/services/tests/servicestests/res/xml/shortcut_2.xml
index 96ed382..f7ea803 100644
--- a/services/tests/servicestests/res/xml/shortcut_2.xml
+++ b/services/tests/servicestests/res/xml/shortcut_2.xml
@@ -17,23 +17,32 @@
<shortcut
android:shortcutId="ms1"
android:enabled="true"
- android:shortcutIcon="@drawable/icon1"
+ android:icon="@drawable/icon1"
android:shortcutShortLabel="@string/shortcut_title1"
android:shortcutLongLabel="@string/shortcut_text1"
android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
- android:shortcutCategories="android.shortcut.conversation:android.shortcut.media"
- android:shortcutIntentAction="action1"
- android:shortcutIntentData="http://a.b.c/"
- />
+ >
+ <intent
+ android:action="action1"
+ android:data="http://a.b.c/"
+ >
+ </intent>
+ <categories android:name="android.shortcut.conversation" />
+ <categories android:name="android.shortcut.media" />
+ </shortcut>
<shortcut
android:shortcutId="ms2"
android:enabled="true"
- android:shortcutIcon="@drawable/icon2"
+ android:icon="@drawable/icon2"
android:shortcutShortLabel="@string/shortcut_title2"
android:shortcutLongLabel="@string/shortcut_text2"
android:shortcutDisabledMessage="@string/shortcut_disabled_message2"
- android:shortcutCategories="android.shortcut.conversation"
- android:shortcutIntentAction="action2"
- android:shortcutIntentData="http://a.b.c/2"
- />
+ >
+ <intent
+ android:action="action2"
+ android:data="http://a.b.c/2"
+ >
+ </intent>
+ <categories android:name="android.shortcut.conversation" />
+ </shortcut>
</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_2_duplicate.xml b/services/tests/servicestests/res/xml/shortcut_2_duplicate.xml
index 2f814b7..b00ec60 100644
--- a/services/tests/servicestests/res/xml/shortcut_2_duplicate.xml
+++ b/services/tests/servicestests/res/xml/shortcut_2_duplicate.xml
@@ -17,11 +17,19 @@
<shortcut
android:shortcutId="ms1"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="action1"
- />
+ >
+ <intent
+ android:action="action1"
+ >
+ </intent>
+ </shortcut>
<shortcut
android:shortcutId="ms1"
android:shortcutShortLabel="@string/shortcut_title2"
- android:shortcutIntentAction="action2"
- />
+ >
+ <intent
+ android:action="action2"
+ >
+ </intent>
+ </shortcut>
</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_3.xml b/services/tests/servicestests/res/xml/shortcut_3.xml
new file mode 100644
index 0000000..432ca49
--- /dev/null
+++ b/services/tests/servicestests/res/xml/shortcut_3.xml
@@ -0,0 +1,56 @@
+<?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.
+-->
+<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
+ <shortcut
+ android:shortcutId="ms1"
+ android:enabled="true"
+ android:icon="@drawable/icon1"
+ android:shortcutShortLabel="@string/shortcut_title1"
+ android:shortcutLongLabel="@string/shortcut_text1"
+ android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
+ >
+ <intent
+ android:action="action1"
+ android:data="http://a.b.c/"
+ >
+ </intent>
+ <categories android:name="android.shortcut.conversation" />
+ <categories android:name="android.shortcut.media" />
+ </shortcut>
+ <shortcut
+ android:shortcutId="ms2"
+ android:enabled="true"
+ android:icon="@drawable/icon2"
+ android:shortcutShortLabel="@string/shortcut_title2"
+ android:shortcutLongLabel="@string/shortcut_text2"
+ android:shortcutDisabledMessage="@string/shortcut_disabled_message2"
+ >
+ <intent
+ android:action="action2"
+ android:data="http://a.b.c/2"
+ >
+ </intent>
+ <categories android:name="android.shortcut.conversation" />
+ </shortcut>
+ <shortcut
+ android:shortcutId="ms3"
+ android:enabled="true"
+ android:icon="@drawable/icon3"
+ android:shortcutShortLabel="@string/shortcut_title2"
+ >
+ <intent android:action="action3" />
+ </shortcut>
+</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_5.xml b/services/tests/servicestests/res/xml/shortcut_5.xml
index 56dba0e..9551100 100644
--- a/services/tests/servicestests/res/xml/shortcut_5.xml
+++ b/services/tests/servicestests/res/xml/shortcut_5.xml
@@ -17,37 +17,69 @@
<shortcut
android:shortcutId="ms1"
android:enabled="true"
- android:shortcutIcon="@drawable/icon1"
+ android:icon="@drawable/icon1"
android:shortcutShortLabel="@string/shortcut_title1"
android:shortcutLongLabel="@string/shortcut_text1"
android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
- android:shortcutCategories="android.shortcut.conversation:android.shortcut.media"
- android:shortcutIntentAction="action1"
- android:shortcutIntentData="http://a.b.c/1"
- />
+ >
+ <intent
+ android:action="action1"
+ android:data="http://a.b.c/1"
+ >
+ </intent>
+ <categories android:name="android.shortcut.conversation" />
+ <categories android:name="android.shortcut.media" />
+ </shortcut>
<shortcut
android:shortcutId="ms2"
android:enabled="true"
- android:shortcutIcon="@drawable/icon2"
+ android:icon="@drawable/icon2"
android:shortcutShortLabel="@string/shortcut_title2"
android:shortcutLongLabel="@string/shortcut_text2"
android:shortcutDisabledMessage="@string/shortcut_disabled_message2"
- android:shortcutCategories="android.shortcut.conversation"
- android:shortcutIntentAction="action2"
- />
+ >
+ <intent
+ android:action="action2"
+ >
+ </intent>
+ <categories android:name="android.shortcut.conversation" />
+ </shortcut>
<shortcut
android:shortcutId="ms3"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="android.intent.action.VIEW"
+ >
+ </intent>
+ </shortcut>
<shortcut
android:shortcutId="ms4"
- android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ android:shortcutShortLabel="@string/shortcut_title2"
+ >
+ <intent
+ android:action="android.intent.action.VIEW2"
+ >
+ </intent>
+ <categories />
+ <categories android:name="" />
+ <categories android:name="cat" />
+ </shortcut>
<shortcut
android:shortcutId="ms5"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="action"
+ android:data="http://www/"
+ android:targetPackage="abc"
+ android:targetClass=".xyz"
+ android:mimeType="foo/bar"
+ >
+ <categories android:name="cat1" />
+ <categories android:name="cat2" />
+ <extra android:name="key1" android:value="value1" />
+ <extra android:name="key2" android:value="value2" />
+ </intent>
+ </shortcut>
</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_5_alt.xml b/services/tests/servicestests/res/xml/shortcut_5_alt.xml
index 74085d9..f79cd6f 100644
--- a/services/tests/servicestests/res/xml/shortcut_5_alt.xml
+++ b/services/tests/servicestests/res/xml/shortcut_5_alt.xml
@@ -17,37 +17,58 @@
<shortcut
android:shortcutId="ms1_alt"
android:enabled="true"
- android:shortcutIcon="@drawable/icon1"
+ android:icon="@drawable/icon1"
android:shortcutShortLabel="@string/shortcut_title1"
android:shortcutLongLabel="@string/shortcut_text1"
android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
- android:shortcutCategories="android.shortcut.conversation:android.shortcut.media"
- android:shortcutIntentAction="action1"
- android:shortcutIntentData="http://a.b.c/1"
- />
+ >
+ <intent
+ android:action="action1"
+ android:data="http://a.b.c/1"
+ >
+ </intent>
+ <categories android:name="android.shortcut.conversation" />
+ <categories android:name="android.shortcut.media" />
+ </shortcut>
<shortcut
android:shortcutId="ms2_alt"
android:enabled="true"
- android:shortcutIcon="@drawable/icon2"
+ android:icon="@drawable/icon2"
android:shortcutShortLabel="@string/shortcut_title2"
android:shortcutLongLabel="@string/shortcut_text2"
android:shortcutDisabledMessage="@string/shortcut_disabled_message2"
- android:shortcutCategories="android.shortcut.conversation"
- android:shortcutIntentAction="action2"
- />
+ >
+ <intent
+ android:action="action2"
+ >
+ </intent>
+ <categories android:name="android.shortcut.conversation" />
+ </shortcut>
<shortcut
android:shortcutId="ms3_alt"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="android.intent.action.VIEW"
+ >
+ </intent>
+ </shortcut>
<shortcut
android:shortcutId="ms4_alt"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="android.intent.action.VIEW"
+ >
+ </intent>
+ </shortcut>
<shortcut
android:shortcutId="ms5_alt"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="android.intent.action.VIEW"
+ >
+ </intent>
+ </shortcut>
</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_5_reverse.xml b/services/tests/servicestests/res/xml/shortcut_5_reverse.xml
index 3d6eb22..d5b7c8f 100644
--- a/services/tests/servicestests/res/xml/shortcut_5_reverse.xml
+++ b/services/tests/servicestests/res/xml/shortcut_5_reverse.xml
@@ -17,37 +17,62 @@
<shortcut
android:shortcutId="ms5"
android:enabled="true"
- android:shortcutIcon="@drawable/icon1"
+ android:icon="@drawable/icon1"
android:shortcutShortLabel="@string/shortcut_title1"
android:shortcutLongLabel="@string/shortcut_text1"
android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
- android:shortcutCategories="android.shortcut.conversation:android.shortcut.media"
- android:shortcutIntentAction="action1"
- android:shortcutIntentData="http://a.b.c/1"
- />
+ >
+ <intent
+ android:action="action1"
+ android:data="http://a.b.c/1"
+ >
+ </intent>
+ <categories android:name="android.shortcut.conversation" />
+ <categories android:name="android.shortcut.media" />
+ </shortcut>
<shortcut
android:shortcutId="ms4"
android:enabled="true"
- android:shortcutIcon="@drawable/icon2"
+ android:icon="@drawable/icon2"
android:shortcutShortLabel="@string/shortcut_title2"
android:shortcutLongLabel="@string/shortcut_text2"
android:shortcutDisabledMessage="@string/shortcut_disabled_message2"
- android:shortcutCategories="android.shortcut.conversation"
- android:shortcutIntentAction="action2"
- />
+ >
+ <intent
+ android:action="action2"
+ >
+ </intent>
+ <categories android:name="android.shortcut.conversation" />
+ </shortcut>
<shortcut
android:shortcutId="ms3"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="android.intent.action.VIEW"
+ >
+ </intent>
+ </shortcut>
<shortcut
android:shortcutId="ms2"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="android.intent.action.VIEW"
+ >
+ </intent>
+ </shortcut>
<shortcut
android:shortcutId="ms1"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="action"
+ >
+ <categories android:name="cat1" />
+ <categories android:name="cat2" />
+ <extra android:name="key1" android:value="value1" />
+ <extra android:name="key2" android:value="value2" />
+ </intent>
+ </shortcut>
</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_error_1.xml b/services/tests/servicestests/res/xml/shortcut_error_1.xml
index 5822496..3990d02 100644
--- a/services/tests/servicestests/res/xml/shortcut_error_1.xml
+++ b/services/tests/servicestests/res/xml/shortcut_error_1.xml
@@ -16,11 +16,19 @@
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
<shortcut
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="android.intent.action.VIEW"
+ >
+ </intent>
+ </shortcut>
<shortcut
android:shortcutId="x1"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="android.intent.action.VIEW"
+ >
+ </intent>
+ </shortcut>
</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_error_2.xml b/services/tests/servicestests/res/xml/shortcut_error_2.xml
index ca67ec7..a6f7150 100644
--- a/services/tests/servicestests/res/xml/shortcut_error_2.xml
+++ b/services/tests/servicestests/res/xml/shortcut_error_2.xml
@@ -16,11 +16,19 @@
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
<shortcut
android:shortcutId="manifest-shortcut-3"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="android.intent.action.VIEW"
+ >
+ </intent>
+ </shortcut>
<shortcut
android:shortcutId="x2"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="android.intent.action.VIEW"
+ >
+ </intent>
+ </shortcut>
</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_error_3.xml b/services/tests/servicestests/res/xml/shortcut_error_3.xml
index fb7b31c..a7b9b84 100644
--- a/services/tests/servicestests/res/xml/shortcut_error_3.xml
+++ b/services/tests/servicestests/res/xml/shortcut_error_3.xml
@@ -21,6 +21,10 @@
<shortcut
android:shortcutId="x3"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="android.intent.action.VIEW"
+ >
+ </intent>
+ </shortcut>
</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_error_4.xml b/services/tests/servicestests/res/xml/shortcut_error_4.xml
new file mode 100644
index 0000000..3697bb4
--- /dev/null
+++ b/services/tests/servicestests/res/xml/shortcut_error_4.xml
@@ -0,0 +1,63 @@
+<?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.
+-->
+<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
+ <!-- This is valid -->
+ <shortcut
+ android:shortcutId="ms1"
+ android:shortcutShortLabel="@string/shortcut_title1"
+ >
+ <intent android:action="action1" />
+ </shortcut>
+
+ <!-- Invalid: no intent -->
+ <shortcut
+ android:shortcutId="ms_ignored1"
+ android:shortcutShortLabel="@string/shortcut_title1"
+ />
+
+ <!-- Valid: more than one intent; first one will be picked. -->
+ <shortcut
+ android:shortcutId="ms2"
+ android:shortcutShortLabel="@string/shortcut_title1"
+ >
+ <intent android:action="action2_1" />
+ <intent android:action="action2_2" />
+ </shortcut>
+
+ <!-- Valid: disabled shortcut doesn't need an intent -->
+ <shortcut
+ android:shortcutId="ms3"
+ android:enabled="false"
+ android:shortcutShortLabel="@string/shortcut_title1"
+ />
+
+ <!-- Valid, but disabled shortcut's intent will be ignored. -->
+ <shortcut
+ android:shortcutId="ms4"
+ android:enabled="false"
+ android:shortcutShortLabel="@string/shortcut_title1"
+ >
+ <intent android:action="action4" />
+ </shortcut>
+
+ <!-- Invalid, no intent action -->
+ <shortcut
+ android:shortcutId="ms_ignored2"
+ android:shortcutShortLabel="@string/shortcut_title1"
+ >
+ <intent android:data="x"/>
+ </shortcut>
+</shortcuts>
diff --git a/services/tests/servicestests/src/android/net/apf/ApfTest.java b/services/tests/servicestests/src/android/net/apf/ApfTest.java
index fae82ca..8ac238a 100644
--- a/services/tests/servicestests/src/android/net/apf/ApfTest.java
+++ b/services/tests/servicestests/src/android/net/apf/ApfTest.java
@@ -552,6 +552,10 @@
assertTrue(mGotApfProgram.block(TIMEOUT_MS));
return mLastApfProgram;
}
+
+ public void assertNoProgramUpdate() {
+ assertFalse(mGotApfProgram.block(TIMEOUT_MS));
+ }
}
private static class TestApfFilter extends ApfFilter {
@@ -863,6 +867,13 @@
verifyRaLifetime(ipManagerCallback, packet, lifetime);
}
+ private void assertInvalidRa(TestApfFilter apfFilter, MockIpManagerCallback ipManagerCallback,
+ ByteBuffer packet) throws IOException, ErrnoException {
+ ipManagerCallback.resetApfProgramWait();
+ apfFilter.pretendPacketReceived(packet.array());
+ ipManagerCallback.assertNoProgramUpdate();
+ }
+
@LargeTest
public void testApfFilterRa() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
@@ -881,6 +892,16 @@
testRaLifetime(apfFilter, ipManagerCallback, basePacket, 1000);
+ // Ensure zero-length options cause the packet to be silently skipped.
+ // Do this before we test other packets. http://b/29586253
+ ByteBuffer zeroLengthOptionPacket = ByteBuffer.wrap(
+ new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
+ basePacket.clear();
+ zeroLengthOptionPacket.put(basePacket);
+ zeroLengthOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE);
+ zeroLengthOptionPacket.put((byte)0);
+ assertInvalidRa(apfFilter, ipManagerCallback, zeroLengthOptionPacket);
+
// Generate several RAs with different options and lifetimes, and verify when
// ApfFilter is shown these packets, it generates programs to filter them for the
// appropriate lifetime.
diff --git a/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProviderTest.java b/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProviderTest.java
index a18737c..c703237 100644
--- a/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProviderTest.java
+++ b/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProviderTest.java
@@ -24,6 +24,7 @@
import android.test.mock.MockContentResolver;
import android.test.mock.MockContext;
import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
import android.util.Log;
import java.util.concurrent.CountDownLatch;
@@ -32,6 +33,7 @@
/**
* Unit tests for FakeSettingsProvider.
*/
+@Suppress
public class FakeSettingsProviderTest extends AndroidTestCase {
private MockContentResolver mCr;
diff --git a/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java b/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java
index b5698d5..3278cf1 100644
--- a/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java
@@ -59,6 +59,15 @@
}
@SmallTest
+ public void testInstantaneousBurstIsEstimatedUnderTwoPercent() throws Exception {
+ assertUpdateTime(mTestStartTime);
+ long eventStart = mTestStartTime + 1000; // start event a long time after initialization
+ long nextEventTime = postEvents(eventStart, 0, 5); // five events at \inf
+ final float rate = mEstimator.getRate(nextEventTime);
+ assertLessThan("Rate", rate, 20f);
+ }
+
+ @SmallTest
public void testCompactBurstIsEstimatedUnderTwoPercent() throws Exception {
assertUpdateTime(mTestStartTime);
long eventStart = mTestStartTime + 1000; // start event a long time after initialization
@@ -110,12 +119,19 @@
assertLessThan("Rate", rate, 0.1f);
}
+ @SmallTest
+ public void testGetRateWithOneUpdate() throws Exception {
+ assertUpdateTime(mTestStartTime);
+ final float rate = mEstimator.getRate(mTestStartTime+1);
+ assertLessThan("Rate", rate, 1f);
+ }
+
private void assertLessThan(String label, float a, float b) {
- assertTrue(String.format("%s was %f, but should be less than %f", label, a, b), a < b);
+ assertTrue(String.format("%s was %f, but should be less than %f", label, a, b), a <= b);
}
private void assertGreaterThan(String label, float a, float b) {
- assertTrue(String.format("%s was %f, but should be more than %f", label, a, b), a > b);
+ assertTrue(String.format("%s was %f, but should be more than %f", label, a, b), a >= b);
}
/** @returns the next event time. */
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 69152d4..71d1a3a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -52,6 +52,7 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.content.pm.ShortcutServiceInternal;
@@ -65,6 +66,7 @@
import android.os.FileUtils;
import android.os.Handler;
import android.os.Looper;
+import android.os.PersistableBundle;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
@@ -97,8 +99,11 @@
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
protected static final String TAG = "ShortcutManagerTest";
@@ -113,6 +118,8 @@
protected static final String[] EMPTY_STRINGS = new String[0]; // Just for readability.
+ protected static final String MAIN_ACTIVITY_CLASS = "MainActivity";
+
// public for mockito
public class BaseContext extends MockContext {
@Override
@@ -310,8 +317,55 @@
}
@Override
- PackageInfo injectGetActivitiesWithMetadata(String packageName, @UserIdInt int userId) {
- return mContext.injectGetActivitiesWithMetadata(packageName, userId);
+ ActivityInfo injectGetActivityInfoWithMetadata(ComponentName activity,
+ @UserIdInt int userId) {
+ final PackageInfo pi = mContext.injectGetActivitiesWithMetadata(
+ activity.getPackageName(), userId);
+ if (pi == null || pi.activities == null) {
+ return null;
+ }
+ for (ActivityInfo ai : pi.activities) {
+ if (!mEnabledActivityChecker.test(ai.getComponentName(), userId)) {
+ continue;
+ }
+ if (activity.equals(ai.getComponentName())) {
+ return ai;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ boolean injectIsMainActivity(@NonNull ComponentName activity, int userId) {
+ if (!mEnabledActivityChecker.test(activity, userId)) {
+ return false;
+ }
+ return mMainActivityChecker.test(activity, userId);
+ }
+
+ @Override
+ List<ResolveInfo> injectGetMainActivities(@NonNull String packageName, int userId) {
+ final PackageInfo pi = mContext.injectGetActivitiesWithMetadata(
+ packageName, userId);
+ if (pi == null || pi.activities == null) {
+ return null;
+ }
+ final ArrayList<ResolveInfo> ret = new ArrayList<>(pi.activities.length);
+ for (int i = 0; i < pi.activities.length; i++) {
+ if (!mEnabledActivityChecker.test(pi.activities[i].getComponentName(), userId)) {
+ continue;
+ }
+ final ResolveInfo ri = new ResolveInfo();
+ ri.activityInfo = pi.activities[i];
+ ret.add(ri);
+ }
+
+ return ret;
+ }
+
+ @Override
+ ComponentName injectGetDefaultMainActivity(@NonNull String packageName, int userId) {
+ return mMainActivityFetcher.apply(packageName, userId);
}
@Override
@@ -334,6 +388,11 @@
}
@Override
+ boolean injectIsSafeModeEnabled() {
+ return mSafeMode;
+ }
+
+ @Override
void wtf(String message, Exception e) {
// During tests, WTF is fatal.
fail(message + " exception: " + e);
@@ -440,6 +499,8 @@
protected File mInjectedFilePathRoot;
+ protected boolean mSafeMode;
+
protected long mInjectedCurrentTimeMillis;
protected boolean mInjectedIsLowRamDevice;
@@ -511,6 +572,15 @@
LAUNCHER_1.equals(callingPackage) || LAUNCHER_2.equals(callingPackage)
|| LAUNCHER_3.equals(callingPackage) || LAUNCHER_4.equals(callingPackage);
+ protected BiPredicate<ComponentName, Integer> mMainActivityChecker =
+ (activity, userId) -> true;
+
+ protected BiFunction<String, Integer, ComponentName> mMainActivityFetcher =
+ (packageName, userId) -> new ComponentName(packageName, MAIN_ACTIVITY_CLASS);
+
+ protected BiPredicate<ComponentName, Integer> mEnabledActivityChecker
+ = (activity, userId) -> true; // all activities are enabled.
+
protected static final long START_TIME = 1440000000101L;
protected static final long INTERVAL = 10000;
@@ -532,7 +602,7 @@
static {
QUERY_ALL.setQueryFlags(
- ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED);
+ ShortcutQuery.FLAG_GET_ALL_KINDS);
}
@Override
@@ -1050,10 +1120,6 @@
+ "/" + ShortcutService.FILENAME_USER_PACKAGES, message);
}
- protected void waitOnMainThread() throws Throwable {
- runTestOnUiThread(() -> {});
- }
-
/**
* Make a shortcut with an ID.
*/
@@ -1134,6 +1200,12 @@
makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
}
+ protected ShortcutInfo makeShortcutWithIntent(String id, Intent intent) {
+ return makeShortcut(
+ id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
+ intent, /* rank =*/ 0);
+ }
+
protected ShortcutInfo makeShortcutWithActivityAndTitle(String id, ComponentName activity,
String title) {
return makeShortcut(
@@ -1153,10 +1225,9 @@
*/
protected ShortcutInfo makeShortcut(String id, String title, ComponentName activity,
Icon icon, Intent intent, int rank) {
- final ShortcutInfo.Builder b = new ShortcutInfo.Builder(mClientContext)
- .setId(id)
+ final ShortcutInfo.Builder b = new ShortcutInfo.Builder(mClientContext, id)
.setActivity(new ComponentName(mClientContext.getPackageName(), "dummy"))
- .setTitle(title)
+ .setShortLabel(title)
.setRank(rank)
.setIntent(intent);
if (icon != null) {
@@ -1173,6 +1244,23 @@
}
/**
+ * Make a shortcut with details.
+ */
+ protected ShortcutInfo makeShortcutWithExtras(String id, Intent intent,
+ PersistableBundle extras) {
+ final ShortcutInfo.Builder b = new ShortcutInfo.Builder(mClientContext, id)
+ .setActivity(new ComponentName(mClientContext.getPackageName(), "dummy"))
+ .setShortLabel("title-" + id)
+ .setExtras(extras)
+ .setIntent(intent);
+ final ShortcutInfo s = b.build();
+
+ s.setTimestamp(mInjectedCurrentTimeMillis); // HACK
+
+ return s;
+ }
+
+ /**
* Make an intent.
*/
protected Intent makeIntent(String action, Class<?> clazz, Object... bundleKeysAndValues) {
@@ -1387,6 +1475,13 @@
return i;
}
+ protected Intent genPackageChangedIntent(String pakcageName, int userId) {
+ Intent i = new Intent(Intent.ACTION_PACKAGE_CHANGED);
+ i.setData(Uri.parse("package:" + pakcageName));
+ i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ return i;
+ }
+
protected Intent genPackageDataClear(String packageName, int userId) {
Intent i = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED);
i.setData(Uri.parse("package:" + packageName));
@@ -1434,7 +1529,7 @@
protected static ShortcutQuery buildAllQuery(String packageName) {
final ShortcutQuery q = new ShortcutQuery();
q.setPackage(packageName);
- q.setQueryFlags(ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED);
+ q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
return q;
}
@@ -1445,6 +1540,12 @@
return q;
}
+ protected static ShortcutQuery buildQueryWithFlags(int queryFlags) {
+ final ShortcutQuery q = new ShortcutQuery();
+ q.setQueryFlags(queryFlags);
+ return q;
+ }
+
protected void backupAndRestore() {
int prevUid = mInjectedCallingUid;
@@ -1584,4 +1685,38 @@
makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3"))));
});
}
+
+ public static List<ShortcutInfo> assertAllHaveIconResId(
+ List<ShortcutInfo> actualShortcuts) {
+ for (ShortcutInfo s : actualShortcuts) {
+ assertTrue("ID " + s.getId() + " not have icon res ID", s.hasIconResource());
+ assertFalse("ID " + s.getId() + " shouldn't have icon FD", s.hasIconFile());
+ }
+ return actualShortcuts;
+ }
+
+ public static List<ShortcutInfo> assertAllHaveIconFile(
+ List<ShortcutInfo> actualShortcuts) {
+ for (ShortcutInfo s : actualShortcuts) {
+ assertFalse("ID " + s.getId() + " shouldn't have icon res ID", s.hasIconResource());
+ assertTrue("ID " + s.getId() + " not have icon FD", s.hasIconFile());
+ }
+ return actualShortcuts;
+ }
+
+ public static List<ShortcutInfo> assertAllHaveIcon(
+ List<ShortcutInfo> actualShortcuts) {
+ for (ShortcutInfo s : actualShortcuts) {
+ assertTrue("ID " + s.getId() + " has no icon ", s.hasIconFile() || s.hasIconResource());
+ }
+ return actualShortcuts;
+ }
+
+ public static List<ShortcutInfo> assertAllStringsResolved(
+ List<ShortcutInfo> actualShortcuts) {
+ for (ShortcutInfo s : actualShortcuts) {
+ assertTrue("ID " + s.getId(), s.hasStringResourcesResolved());
+ }
+ return actualShortcuts;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index fc1ebbe..7d33a30 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -19,9 +19,6 @@
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllDynamic;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllDynamicOrPinned;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllEnabled;
-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllHaveIcon;
-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllHaveIconFile;
-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllHaveIconResId;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllHaveIntents;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllHaveTitle;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllImmutable;
@@ -32,7 +29,6 @@
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllNotKeyFieldsOnly;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllNotManifest;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllPinned;
-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllStringsResolved;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllUnique;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertBitmapSize;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertBundleEmpty;
@@ -44,6 +40,7 @@
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertDynamicShortcutCountExceeded;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertEmpty;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertForLauncherCallback;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertShortcutIds;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.filterByActivity;
@@ -54,6 +51,7 @@
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.pfdToBitmap;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.resetAll;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.set;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.waitOnMainThread;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
@@ -88,6 +86,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.pm.shortcutmanagertest.ShortcutManagerTestUtils.ShortcutListAsserter;
import org.mockito.ArgumentCaptor;
@@ -95,6 +94,9 @@
import java.io.IOException;
import java.util.List;
import java.util.Locale;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
/**
* Tests for ShortcutService and ShortcutManager.
@@ -191,7 +193,7 @@
+ ConfigConstants.KEY_ICON_FORMAT + "=WEBP,"
+ ConfigConstants.KEY_ICON_QUALITY + "=75");
assertEquals(123000, mService.getResetIntervalForTest());
- assertEquals(4, mService.getMaxDynamicShortcutsForTest());
+ assertEquals(4, mService.getMaxShortcutsForTest());
assertEquals(5, mService.getMaxUpdatesPerIntervalForTest());
assertEquals(100, mService.getMaxIconDimensionForTest());
assertEquals(CompressFormat.WEBP, mService.getIconPersistFormatForTest());
@@ -206,7 +208,7 @@
mService.getResetIntervalForTest());
assertEquals(ShortcutService.DEFAULT_MAX_SHORTCUTS_PER_APP,
- mService.getMaxDynamicShortcutsForTest());
+ mService.getMaxShortcutsForTest());
assertEquals(ShortcutService.DEFAULT_MAX_UPDATES_PER_INTERVAL,
mService.getMaxUpdatesPerIntervalForTest());
@@ -351,6 +353,127 @@
});
}
+ public void testPublishWithNoActivity() {
+ // If activity is not explicitly set, use the default one.
+
+ runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
+ // s1 and s3 has no activities.
+ final ShortcutInfo si1 = new ShortcutInfo.Builder(mClientContext, "si1")
+ .setShortLabel("label1")
+ .setIntent(new Intent("action1"))
+ .build();
+ final ShortcutInfo si2 = new ShortcutInfo.Builder(mClientContext, "si2")
+ .setShortLabel("label2")
+ .setActivity(new ComponentName(getCallingPackage(), "abc"))
+ .setIntent(new Intent("action2"))
+ .build();
+ final ShortcutInfo si3 = new ShortcutInfo.Builder(mClientContext, "si3")
+ .setShortLabel("label3")
+ .setIntent(new Intent("action3"))
+ .build();
+
+ // Set test 1
+ assertTrue(mManager.setDynamicShortcuts(list(si1)));
+
+ assertWith(getCallerShortcuts())
+ .haveIds("si1")
+ .forShortcutWithId("si1", si -> {
+ assertEquals(new ComponentName(getCallingPackage(),
+ MAIN_ACTIVITY_CLASS), si.getActivity());
+ });
+
+ // Set test 2
+ assertTrue(mManager.setDynamicShortcuts(list(si2, si1)));
+
+ assertWith(getCallerShortcuts())
+ .haveIds("si1", "si2")
+ .forShortcutWithId("si1", si -> {
+ assertEquals(new ComponentName(getCallingPackage(),
+ MAIN_ACTIVITY_CLASS), si.getActivity());
+ })
+ .forShortcutWithId("si2", si -> {
+ assertEquals(new ComponentName(getCallingPackage(),
+ "abc"), si.getActivity());
+ });
+
+
+ // Set test 3
+ assertTrue(mManager.setDynamicShortcuts(list(si3, si1)));
+
+ assertWith(getCallerShortcuts())
+ .haveIds("si1", "si3")
+ .forShortcutWithId("si1", si -> {
+ assertEquals(new ComponentName(getCallingPackage(),
+ MAIN_ACTIVITY_CLASS), si.getActivity());
+ })
+ .forShortcutWithId("si3", si -> {
+ assertEquals(new ComponentName(getCallingPackage(),
+ MAIN_ACTIVITY_CLASS), si.getActivity());
+ });
+
+ mInjectedCurrentTimeMillis += INTERVAL; // reset throttling
+
+ // Add test 1
+ mManager.removeAllDynamicShortcuts();
+ assertTrue(mManager.addDynamicShortcuts(list(si1)));
+
+ assertWith(getCallerShortcuts())
+ .haveIds("si1")
+ .forShortcutWithId("si1", si -> {
+ assertEquals(new ComponentName(getCallingPackage(),
+ MAIN_ACTIVITY_CLASS), si.getActivity());
+ });
+
+ // Add test 2
+ mManager.removeAllDynamicShortcuts();
+ assertTrue(mManager.addDynamicShortcuts(list(si2, si1)));
+
+ assertWith(getCallerShortcuts())
+ .haveIds("si1", "si2")
+ .forShortcutWithId("si1", si -> {
+ assertEquals(new ComponentName(getCallingPackage(),
+ MAIN_ACTIVITY_CLASS), si.getActivity());
+ })
+ .forShortcutWithId("si2", si -> {
+ assertEquals(new ComponentName(getCallingPackage(),
+ "abc"), si.getActivity());
+ });
+
+
+ // Add test 3
+ mManager.removeAllDynamicShortcuts();
+ assertTrue(mManager.addDynamicShortcuts(list(si3, si1)));
+
+ assertWith(getCallerShortcuts())
+ .haveIds("si1", "si3")
+ .forShortcutWithId("si1", si -> {
+ assertEquals(new ComponentName(getCallingPackage(),
+ MAIN_ACTIVITY_CLASS), si.getActivity());
+ })
+ .forShortcutWithId("si3", si -> {
+ assertEquals(new ComponentName(getCallingPackage(),
+ MAIN_ACTIVITY_CLASS), si.getActivity());
+ });
+ });
+ }
+
+ public void testPublishWithNoActivity_noMainActivityInPackage() {
+ runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
+ final ShortcutInfo si1 = new ShortcutInfo.Builder(mClientContext, "si1")
+ .setShortLabel("label1")
+ .setIntent(new Intent("action1"))
+ .build();
+
+ // Returning null means there's no main activity in this package.
+ mMainActivityFetcher = (packageName, userId) -> null;
+
+ assertExpectException(
+ RuntimeException.class, "Launcher activity not found for", () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(si1)));
+ });
+ });
+ }
+
public void testDeleteDynamicShortcuts() {
final ShortcutInfo si1 = makeShortcut("shortcut1");
final ShortcutInfo si2 = makeShortcut("shortcut2");
@@ -1102,6 +1225,117 @@
// TODO More tests: pinned but dynamic.
}
+ public void testGetShortcuts_shortcutKinds() throws Exception {
+ // Create 3 manifest and 3 dynamic shortcuts
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+ R.xml.shortcut_3);
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+ });
+
+ // Pin 2 and 3
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2", "ms3", "s2", "s3"),
+ HANDLE_USER_0);
+ });
+
+ // Remove ms3 and s3
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+ R.xml.shortcut_2);
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"))));
+ });
+
+ // Check their status.
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms2", "ms3", "s1", "s2", "s3")
+
+ .selectByIds("ms1", "ms2")
+ .areAllManifest()
+ .areAllImmutable()
+ .areAllNotDynamic()
+
+ .revertToOriginalList()
+ .selectByIds("ms3")
+ .areAllNotManifest()
+ .areAllImmutable()
+ .areAllDisabled()
+ .areAllNotDynamic()
+
+ .revertToOriginalList()
+ .selectByIds("s1", "s2")
+ .areAllNotManifest()
+ .areAllMutable()
+ .areAllDynamic()
+
+ .revertToOriginalList()
+ .selectByIds("s3")
+ .areAllNotManifest()
+ .areAllMutable()
+ .areAllEnabled()
+ .areAllNotDynamic()
+
+ .revertToOriginalList()
+ .selectByIds("s1", "ms1")
+ .areAllNotPinned()
+
+ .revertToOriginalList()
+ .selectByIds("s2", "s3", "ms2", "ms3")
+ .areAllPinned()
+ ;
+ });
+
+ // Finally, actual tests.
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertWith(mLauncherApps.getShortcuts(
+ buildQueryWithFlags(ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0))
+ .haveIds("s1", "s2");
+ assertWith(mLauncherApps.getShortcuts(
+ buildQueryWithFlags(ShortcutQuery.FLAG_GET_MANIFEST), HANDLE_USER_0))
+ .haveIds("ms1", "ms2");
+ assertWith(mLauncherApps.getShortcuts(
+ buildQueryWithFlags(ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0))
+ .haveIds("s2", "s3", "ms2", "ms3");
+
+ assertWith(mLauncherApps.getShortcuts(
+ buildQueryWithFlags(
+ ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED
+ ), HANDLE_USER_0))
+ .haveIds("s1", "s2", "s3", "ms2", "ms3");
+
+ assertWith(mLauncherApps.getShortcuts(
+ buildQueryWithFlags(
+ ShortcutQuery.FLAG_GET_MANIFEST | ShortcutQuery.FLAG_GET_PINNED
+ ), HANDLE_USER_0))
+ .haveIds("ms1", "s2", "s3", "ms2", "ms3");
+
+ assertWith(mLauncherApps.getShortcuts(
+ buildQueryWithFlags(
+ ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_MANIFEST
+ ), HANDLE_USER_0))
+ .haveIds("ms1", "ms2", "s1", "s2");
+
+ assertWith(mLauncherApps.getShortcuts(
+ buildQueryWithFlags(
+ ShortcutQuery.FLAG_GET_ALL_KINDS
+ ), HANDLE_USER_0))
+ .haveIds("ms1", "ms2", "ms3", "s1", "s2", "s3");
+ });
+ }
+
public void testGetShortcuts_resolveStrings() throws Exception {
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
ShortcutInfo si = new ShortcutInfo.Builder(mClientContext)
@@ -2223,137 +2457,167 @@
}
public void testLauncherCallback() throws Throwable {
- LauncherApps.Callback c0 = mock(LauncherApps.Callback.class);
-
- // Set listeners
-
- runWithCaller(LAUNCHER_1, USER_0, () -> {
- mLauncherApps.registerCallback(c0, new Handler(Looper.getMainLooper()));
- });
-
- runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
- assertTrue(mManager.setDynamicShortcuts(list(
- makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
- });
-
- waitOnMainThread();
- ArgumentCaptor<List> shortcuts = ArgumentCaptor.forClass(List.class);
- verify(c0).onShortcutsChanged(
- eq(CALLING_PACKAGE_1),
- shortcuts.capture(),
- eq(HANDLE_USER_0)
+ // Disable throttling for this test.
+ mService.updateConfigurationLocked(
+ ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "=99999999,"
+ + ConfigConstants.KEY_MAX_SHORTCUTS + "=99999999"
);
- assertShortcutIds(assertAllDynamic(shortcuts.getValue()),
- "s1", "s2", "s3");
+
+ setCaller(LAUNCHER_1, USER_0);
+
+ assertForLauncherCallback(mLauncherApps, () -> {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+ });
+ }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
+ .haveIds("s1", "s2", "s3")
+ .areAllWithKeyFieldsOnly()
+ .areAllDynamic();
// From different package.
- reset(c0);
- runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
- assertTrue(mManager.setDynamicShortcuts(list(
- makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
- });
- waitOnMainThread();
- shortcuts = ArgumentCaptor.forClass(List.class);
- verify(c0).onShortcutsChanged(
- eq(CALLING_PACKAGE_2),
- shortcuts.capture(),
- eq(HANDLE_USER_0)
- );
- assertShortcutIds(assertAllDynamic(shortcuts.getValue()),
- "s1", "s2", "s3");
+ assertForLauncherCallback(mLauncherApps, () -> {
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+ });
+ }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_2, HANDLE_USER_0)
+ .haveIds("s1", "s2", "s3")
+ .areAllWithKeyFieldsOnly()
+ .areAllDynamic();
// Different user, callback shouldn't be called.
- reset(c0);
- runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
- assertTrue(mManager.setDynamicShortcuts(list(
- makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
- });
- waitOnMainThread();
- verify(c0, times(0)).onShortcutsChanged(
- anyString(),
- any(List.class),
- any(UserHandle.class)
- );
+ assertForLauncherCallback(mLauncherApps, () -> {
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+ });
+ }).assertNoCallbackCalled();
+
// Test for addDynamicShortcuts.
- reset(c0);
- runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
- dumpsysOnLogcat("before addDynamicShortcuts");
- assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s4"))));
- });
-
- waitOnMainThread();
- shortcuts = ArgumentCaptor.forClass(List.class);
- verify(c0).onShortcutsChanged(
- eq(CALLING_PACKAGE_1),
- shortcuts.capture(),
- eq(HANDLE_USER_0)
- );
- assertShortcutIds(assertAllDynamic(shortcuts.getValue()),
- "s1", "s2", "s3", "s4");
+ assertForLauncherCallback(mLauncherApps, () -> {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s4"))));
+ });
+ }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
+ .haveIds("s1", "s2", "s3", "s4")
+ .areAllWithKeyFieldsOnly()
+ .areAllDynamic();
// Test for remove
- reset(c0);
- runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
- mManager.removeDynamicShortcuts(list("s1"));
- });
-
- waitOnMainThread();
- shortcuts = ArgumentCaptor.forClass(List.class);
- verify(c0).onShortcutsChanged(
- eq(CALLING_PACKAGE_1),
- shortcuts.capture(),
- eq(HANDLE_USER_0)
- );
- assertShortcutIds(assertAllDynamic(shortcuts.getValue()),
- "s2", "s3", "s4");
+ assertForLauncherCallback(mLauncherApps, () -> {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.removeDynamicShortcuts(list("s1"));
+ });
+ }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
+ .haveIds("s2", "s3", "s4")
+ .areAllWithKeyFieldsOnly()
+ .areAllDynamic();
// Test for update
- reset(c0);
+ assertForLauncherCallback(mLauncherApps, () -> {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.updateShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"))));
+ });
+ }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
+ // All remaining shortcuts will be passed regardless of what's been updated.
+ .haveIds("s2", "s3", "s4")
+ .areAllWithKeyFieldsOnly()
+ .areAllDynamic();
+
+ // Test for deleteAll
+ assertForLauncherCallback(mLauncherApps, () -> {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.removeAllDynamicShortcuts();
+ });
+ }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
+ .isEmpty();
+
+ // Update package1 with manifest shortcuts
+ assertForLauncherCallback(mLauncherApps, () -> {
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+ R.xml.shortcut_2);
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+ }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
+ .areAllManifest()
+ .areAllWithKeyFieldsOnly()
+ .haveIds("ms1", "ms2");
+
+ // Make sure pinned shortcuts are passed too.
+ // 1. Add dynamic shortcuts.
runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
- assertTrue(mManager.updateShortcuts(list(
+ assertTrue(mManager.setDynamicShortcuts(list(
makeShortcut("s1"), makeShortcut("s2"))));
});
- waitOnMainThread();
- shortcuts = ArgumentCaptor.forClass(List.class);
- verify(c0).onShortcutsChanged(
- eq(CALLING_PACKAGE_1),
- shortcuts.capture(),
- eq(HANDLE_USER_0)
- );
- assertShortcutIds(assertAllDynamic(shortcuts.getValue()),
- "s2", "s3", "s4");
-
- // Test for deleteAll
- reset(c0);
+ // 2. Pin some.
+ runWithCaller(LAUNCHER_1, UserHandle.USER_SYSTEM, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2", "s2"), HANDLE_USER_0);
+ });
runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
- mManager.removeAllDynamicShortcuts();
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms2", "s1", "s2")
+ .areAllEnabled()
+
+ .selectByIds("ms1", "ms2")
+ .areAllManifest()
+
+ .revertToOriginalList()
+ .selectByIds("s1", "s2")
+ .areAllDynamic()
+ ;
});
- waitOnMainThread();
- shortcuts = ArgumentCaptor.forClass(List.class);
- verify(c0).onShortcutsChanged(
- eq(CALLING_PACKAGE_1),
- shortcuts.capture(),
- eq(HANDLE_USER_0)
- );
- assertEquals(0, shortcuts.getValue().size());
+ // 3 Update the app with no manifest shortcuts. (Pinned one will survive.)
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+ R.xml.shortcut_0);
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+ assertForLauncherCallback(mLauncherApps, () -> {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.removeDynamicShortcuts(list("s2"));
+
+ assertWith(getCallerShortcuts())
+ .haveIds("ms2", "s1", "s2")
+
+ .selectByIds("ms2")
+ .areAllNotManifest()
+ .areAllPinned()
+ .areAllImmutable()
+ .areAllDisabled()
+
+ .revertToOriginalList()
+ .selectByIds("s1")
+ .areAllDynamic()
+ .areAllNotPinned()
+ .areAllEnabled()
+
+ .revertToOriginalList()
+ .selectByIds("s2")
+ .areAllNotDynamic()
+ .areAllPinned()
+ .areAllEnabled()
+ ;
+ });
+ }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
+ .haveIds("ms2", "s1", "s2")
+ .areAllWithKeyFieldsOnly();
// 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.
- waitOnMainThread();
- shortcuts = ArgumentCaptor.forClass(List.class);
- verify(c0).onShortcutsChanged(
- eq(CALLING_PACKAGE_2),
- shortcuts.capture(),
- eq(HANDLE_USER_0)
- );
- assertEquals(0, shortcuts.getValue().size());
+ assertForLauncherCallback(mLauncherApps, () -> {
+ uninstallPackage(USER_0, CALLING_PACKAGE_2);
+ mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_0, USER_0,
+ /* appStillExists = */ false);
+ }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_2, HANDLE_USER_0)
+ .isEmpty();
}
public void testLauncherCallback_crossProfile() throws Throwable {
@@ -2753,7 +3017,7 @@
// Nonexistent package.
uninstallPackage(USER_0, "abc");
- mService.cleanUpPackageLocked("abc", USER_0, USER_0);
+ mService.cleanUpPackageLocked("abc", USER_0, USER_0, /* appStillExists = */ false);
// No changes.
assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
@@ -2785,7 +3049,8 @@
// Remove a package.
uninstallPackage(USER_0, CALLING_PACKAGE_1);
- mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_0, USER_0);
+ mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_0, USER_0,
+ /* appStillExists = */ false);
assertEquals(set(CALLING_PACKAGE_2),
hashSet(user0.getAllPackagesForTest().keySet()));
@@ -2816,7 +3081,7 @@
// Remove a launcher.
uninstallPackage(USER_10, LAUNCHER_1);
- mService.cleanUpPackageLocked(LAUNCHER_1, USER_10, USER_10);
+ mService.cleanUpPackageLocked(LAUNCHER_1, USER_10, USER_10, /* appStillExists = */ false);
assertEquals(set(CALLING_PACKAGE_2),
hashSet(user0.getAllPackagesForTest().keySet()));
@@ -2844,7 +3109,8 @@
// Remove a package.
uninstallPackage(USER_10, CALLING_PACKAGE_2);
- mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_10, USER_10);
+ mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_10, USER_10,
+ /* appStillExists = */ false);
assertEquals(set(CALLING_PACKAGE_2),
hashSet(user0.getAllPackagesForTest().keySet()));
@@ -2872,7 +3138,8 @@
// Remove the other launcher from user 10 too.
uninstallPackage(USER_10, LAUNCHER_2);
- mService.cleanUpPackageLocked(LAUNCHER_2, USER_10, USER_10);
+ mService.cleanUpPackageLocked(LAUNCHER_2, USER_10, USER_10,
+ /* appStillExists = */ false);
assertEquals(set(CALLING_PACKAGE_2),
hashSet(user0.getAllPackagesForTest().keySet()));
@@ -2900,7 +3167,8 @@
// More remove.
uninstallPackage(USER_10, CALLING_PACKAGE_1);
- mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_10, USER_10);
+ mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_10, USER_10,
+ /* appStillExists = */ false);
assertEquals(set(CALLING_PACKAGE_2),
hashSet(user0.getAllPackagesForTest().keySet()));
@@ -2926,6 +3194,74 @@
mService.saveDirtyInfo();
}
+ public void testCleanupPackage_republishManifests() {
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+ R.xml.shortcut_2);
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+ });
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+ list("s2", "s3", "ms1", "ms2"), HANDLE_USER_0);
+ });
+
+ // Remove ms2 from manifest.
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+ R.xml.shortcut_1);
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"))));
+
+ // Make sure the shortcuts are in the intended state.
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms2", "s1", "s2", "s3")
+
+ .selectByIds("ms1")
+ .areAllManifest()
+ .areAllPinned()
+
+ .revertToOriginalList()
+ .selectByIds("ms2")
+ .areAllNotManifest()
+ .areAllPinned()
+
+ .revertToOriginalList()
+ .selectByIds("s1")
+ .areAllDynamic()
+ .areAllNotPinned()
+
+ .revertToOriginalList()
+ .selectByIds("s2")
+ .areAllDynamic()
+ .areAllPinned()
+
+ .revertToOriginalList()
+ .selectByIds("s3")
+ .areAllNotDynamic()
+ .areAllPinned();
+ });
+
+ // Clean up + re-publish manifests.
+ mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_0, USER_0,
+ /* appStillExists = */ true);
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1")
+ .areAllManifest();
+ });
+ }
+
public void testHandleGonePackage_crossProfile() {
// Create some shortcuts.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -3237,6 +3573,20 @@
assertTrue(mManager.addDynamicShortcuts(list(
makeShortcutWithIcon("s1", bmp32x32), makeShortcutWithIcon("s2", bmp32x32)
)));
+ // Also add a manifest shortcut, which should be removed too.
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+ R.xml.shortcut_1);
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("s1", "s2", "ms1")
+
+ .selectManifest()
+ .haveIds("ms1");
+ });
setCaller(CALLING_PACKAGE_2, USER_0);
assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
@@ -3412,8 +3762,47 @@
assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
}
- public void testHandlePackageUpdate() throws Throwable {
+ public void testHandlePackageClearData_manifestRepublished() {
+ // Add two manifests and two dynamics.
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+ R.xml.shortcut_2);
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_10));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertTrue(mManager.addDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"))));
+ });
+ runWithCaller(LAUNCHER_1, USER_10, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2", "s2"), HANDLE_USER_10);
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms2", "s1", "s2")
+ .areAllEnabled()
+
+ .selectPinned()
+ .haveIds("ms2", "s2");
+ });
+
+ // Clear data
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageDataClear(CALLING_PACKAGE_1, USER_10));
+
+ // Only manifest shortcuts will remain, and are no longer pinned.
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms2")
+ .areAllEnabled()
+ .areAllNotPinned();
+ });
+ }
+
+ public void testHandlePackageUpdate() throws Throwable {
// Set up shortcuts and launchers.
final Icon res32x32 = Icon.createWithResource(getTestContext(), R.drawable.black_32x32);
@@ -3677,6 +4066,202 @@
});
}
+ public void testHandlePackageChanged() {
+ final ComponentName ACTIVITY1 = new ComponentName(CALLING_PACKAGE_1, "act1");
+ final ComponentName ACTIVITY2 = new ComponentName(CALLING_PACKAGE_1, "act2");
+
+ addManifestShortcutResource(ACTIVITY1, R.xml.shortcut_1);
+ addManifestShortcutResource(ACTIVITY2, R.xml.shortcut_1_alt);
+
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_10));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertTrue(mManager.addDynamicShortcuts(list(
+ makeShortcutWithActivity("s1", ACTIVITY1),
+ makeShortcutWithActivity("s2", ACTIVITY2)
+ )));
+ });
+ runWithCaller(LAUNCHER_1, USER_10, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms1-alt", "s2"), HANDLE_USER_10);
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms1-alt", "s1", "s2")
+ .areAllEnabled()
+
+ .selectPinned()
+ .haveIds("ms1-alt", "s2")
+
+ .revertToOriginalList()
+ .selectByIds("ms1", "s1")
+ .areAllWithActivity(ACTIVITY1)
+
+ .revertToOriginalList()
+ .selectByIds("ms1-alt", "s2")
+ .areAllWithActivity(ACTIVITY2)
+ ;
+ });
+
+ // First, no changes.
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageChangedIntent(CALLING_PACKAGE_1, USER_10));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms1-alt", "s1", "s2")
+ .areAllEnabled()
+
+ .selectPinned()
+ .haveIds("ms1-alt", "s2")
+
+ .revertToOriginalList()
+ .selectByIds("ms1", "s1")
+ .areAllWithActivity(ACTIVITY1)
+
+ .revertToOriginalList()
+ .selectByIds("ms1-alt", "s2")
+ .areAllWithActivity(ACTIVITY2)
+ ;
+ });
+
+ // Disable activity 1
+ mEnabledActivityChecker = (activity, userId) -> !ACTIVITY1.equals(activity);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageChangedIntent(CALLING_PACKAGE_1, USER_10));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1-alt", "s2")
+ .areAllEnabled()
+
+ .selectPinned()
+ .haveIds("ms1-alt", "s2")
+
+ .revertToOriginalList()
+ .selectByIds("ms1-alt", "s2")
+ .areAllWithActivity(ACTIVITY2)
+ ;
+ });
+
+ // Re-enable activity 1.
+ // Manifest shortcuts will be re-published, but dynamic ones are not.
+ mEnabledActivityChecker = (activity, userId) -> true;
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageChangedIntent(CALLING_PACKAGE_1, USER_10));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms1-alt", "s2")
+ .areAllEnabled()
+
+ .selectPinned()
+ .haveIds("ms1-alt", "s2")
+
+ .revertToOriginalList()
+ .selectByIds("ms1")
+ .areAllWithActivity(ACTIVITY1)
+
+ .revertToOriginalList()
+ .selectByIds("ms1-alt", "s2")
+ .areAllWithActivity(ACTIVITY2)
+ ;
+ });
+
+ // Disable activity 2
+ // Because "ms1-alt" and "s2" are both pinned, they will remain, but disabled.
+ mEnabledActivityChecker = (activity, userId) -> !ACTIVITY2.equals(activity);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageChangedIntent(CALLING_PACKAGE_1, USER_10));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms1-alt", "s2")
+
+ .selectDynamic().isEmpty().revertToOriginalList() // no dynamics.
+
+ .selectPinned()
+ .haveIds("ms1-alt", "s2")
+ .areAllDisabled()
+
+ .revertToOriginalList()
+ .selectByIds("ms1")
+ .areAllWithActivity(ACTIVITY1)
+ .areAllEnabled()
+ ;
+ });
+ }
+
+ public void testHandlePackageUpdate_activityNoLongerMain() throws Throwable {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcutWithActivity("s1a",
+ new ComponentName(getCallingPackage(), "act1")),
+ makeShortcutWithActivity("s1b",
+ new ComponentName(getCallingPackage(), "act1")),
+ makeShortcutWithActivity("s2a",
+ new ComponentName(getCallingPackage(), "act2")),
+ makeShortcutWithActivity("s2b",
+ new ComponentName(getCallingPackage(), "act2")),
+ makeShortcutWithActivity("s3a",
+ new ComponentName(getCallingPackage(), "act3")),
+ makeShortcutWithActivity("s3b",
+ new ComponentName(getCallingPackage(), "act3"))
+ )));
+ assertWith(getCallerShortcuts())
+ .haveIds("s1a", "s1b", "s2a", "s2b", "s3a", "s3b")
+ .areAllDynamic();
+ });
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+ list("s1b", "s2b", "s3b"),
+ HANDLE_USER_0);
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("s1a", "s1b", "s2a", "s2b", "s3a", "s3b")
+ .areAllDynamic()
+
+ .selectByIds("s1b", "s2b", "s3b")
+ .areAllPinned();
+ });
+
+ // Update the app and act2 and act3 are no longer main.
+ mMainActivityChecker = (activity, userId) -> {
+ return activity.getClassName().equals("act1");
+ };
+
+ setCaller(LAUNCHER_1, USER_0);
+ assertForLauncherCallback(mLauncherApps, () -> {
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0));
+ }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
+ // Make sure the launcher gets callbacks.
+ .haveIds("s1a", "s1b", "s2b", "s3b")
+ .areAllWithKeyFieldsOnly();
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ // s2a and s3a are gone, but s2b and s3b will remain because they're pinned, and
+ // disabled.
+ assertWith(getCallerShortcuts())
+ .haveIds("s1a", "s1b", "s2b", "s3b")
+
+ .selectByIds("s1a", "s1b")
+ .areAllDynamic()
+ .areAllEnabled()
+
+ .revertToOriginalList()
+ .selectByIds("s2b", "s3b")
+ .areAllNotDynamic()
+ .areAllDisabled()
+ .areAllPinned()
+ ;
+ });
+ }
+
protected void prepareForBackupTest() {
prepareCrossProfileDataSet();
@@ -4394,11 +4979,11 @@
public void testOnApplicationActive_permission() {
assertExpectException(SecurityException.class, "Missing permission", () ->
- mService.onApplicationActive(CALLING_PACKAGE_1, USER_0));
+ mManager.onApplicationActive(CALLING_PACKAGE_1, USER_0));
// Has permission, now it should pass.
mCallerPermissions.add(permission.RESET_SHORTCUT_MANAGER_THROTTLING);
- mService.onApplicationActive(CALLING_PACKAGE_1, USER_0);
+ mManager.onApplicationActive(CALLING_PACKAGE_1, USER_0);
}
public void testDumpsys_crossProfile() {
@@ -4884,6 +5469,117 @@
});
}
+ public void testManifestShortcuts_intentDefinitions() {
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+ R.xml.shortcut_error_4);
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ // Make sure invalid ones are not published.
+ // Note that at this point disabled ones don't show up because they weren't pinned.
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms2")
+ .areAllManifest()
+ .areAllNotDynamic()
+ .areAllNotPinned()
+ .areAllImmutable()
+ .areAllEnabled()
+ .forShortcutWithId("ms1", si -> {
+ assertTrue(si.isEnabled());
+ assertEquals("action1", si.getIntent().getAction());
+ })
+ .forShortcutWithId("ms2", si -> {
+ assertTrue(si.isEnabled());
+ assertEquals("action2_1", si.getIntent().getAction());
+ });
+ });
+
+ // Publish 5 enabled to pin some, so we can later test disabled manfiest shortcuts..
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+ R.xml.shortcut_5);
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ // Make sure 5 manifest shortcuts are published.
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms2", "ms3", "ms4", "ms5")
+ .areAllManifest()
+ .areAllNotDynamic()
+ .areAllNotPinned()
+ .areAllImmutable()
+ .areAllEnabled();
+ });
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+ list("ms3", "ms4", "ms5"), HANDLE_USER_0);
+ });
+
+ // Make sure they're pinned.
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms2", "ms3", "ms4", "ms5")
+ .selectByIds("ms1", "ms2")
+ .areAllNotPinned()
+ .areAllEnabled()
+
+ .revertToOriginalList()
+ .selectByIds("ms3", "ms4", "ms5")
+ .areAllPinned()
+ .areAllEnabled();
+ });
+
+ // Update the app.
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+ R.xml.shortcut_error_4);
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+ // Make sure 3, 4 and 5 still exist but disabled.
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms2", "ms3", "ms4", "ms5")
+ .areAllNotDynamic()
+ .areAllImmutable()
+
+ .selectByIds("ms1", "ms2")
+ .areAllManifest()
+ .areAllNotPinned()
+ .areAllEnabled()
+
+ .revertToOriginalList()
+ .selectByIds("ms3", "ms4", "ms5")
+ .areAllNotManifest()
+ .areAllPinned()
+ .areAllDisabled()
+
+ .revertToOriginalList()
+ .forShortcutWithId("ms1", si -> {
+ assertEquals(si.getId(), "action1", si.getIntent().getAction());
+ })
+ .forShortcutWithId("ms2", si -> {
+ assertEquals(si.getId(), "action2_1", si.getIntent().getAction());
+ })
+ .forShortcutWithId("ms3", si -> {
+ assertEquals(si.getId(), Intent.ACTION_VIEW, si.getIntent().getAction());
+ })
+ .forShortcutWithId("ms4", si -> {
+ assertEquals(si.getId(), Intent.ACTION_VIEW, si.getIntent().getAction());
+ })
+ .forShortcutWithId("ms5", si -> {
+ assertEquals(si.getId(), "action", si.getIntent().getAction());
+ });
+ });
+ }
+
public void testManifestShortcuts_checkAllFields() {
mService.handleUnlockUser(USER_0);
@@ -4897,63 +5593,95 @@
// Only the valid one is published.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
- mManager.getManifestShortcuts()))),
- "ms1", "ms2", "ms3", "ms4", "ms5");
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms2", "ms3", "ms4", "ms5")
+ .areAllManifest()
+ .areAllImmutable()
+ .areAllEnabled()
+ .areAllNotPinned()
+ .areAllNotDynamic()
- // check first shortcut.
- ShortcutInfo si = getCallerShortcut("ms1");
+ .forShortcutWithId("ms1", si -> {
+ assertEquals(R.drawable.icon1, si.getIconResourceId());
+ assertEquals(new ComponentName(CALLING_PACKAGE_1,
+ ShortcutActivity.class.getName()),
+ si.getActivity());
- assertEquals("ms1", si.getId());
- assertEquals(R.drawable.icon1, si.getIconResourceId());
- assertEquals(new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
- si.getActivity());
+ assertEquals(R.string.shortcut_title1, si.getTitleResId());
+ assertEquals("r" + R.string.shortcut_title1, si.getTitleResName());
+ assertEquals(R.string.shortcut_text1, si.getTextResId());
+ assertEquals("r" + R.string.shortcut_text1, si.getTextResName());
+ assertEquals(R.string.shortcut_disabled_message1,
+ si.getDisabledMessageResourceId());
+ assertEquals("r" + R.string.shortcut_disabled_message1,
+ si.getDisabledMessageResName());
- assertEquals(R.string.shortcut_title1, si.getTitleResId());
- assertEquals("r" + R.string.shortcut_title1, si.getTitleResName());
- assertEquals(R.string.shortcut_text1, si.getTextResId());
- assertEquals("r" + R.string.shortcut_text1, si.getTextResName());
- assertEquals(R.string.shortcut_disabled_message1, si.getDisabledMessageResourceId());
- assertEquals("r" + R.string.shortcut_disabled_message1, si.getDisabledMessageResName());
+ assertEquals(set("android.shortcut.conversation", "android.shortcut.media"),
+ si.getCategories());
+ assertEquals("action1", si.getIntent().getAction());
+ assertEquals(Uri.parse("http://a.b.c/1"), si.getIntent().getData());
+ })
- assertEquals(set("android.shortcut.conversation", "android.shortcut.media"),
- si.getCategories());
- assertEquals("action1", si.getIntent().getAction());
- assertEquals(Uri.parse("http://a.b.c/1"), si.getIntent().getData());
+ .forShortcutWithId("ms2", si -> {
+ assertEquals("ms2", si.getId());
+ assertEquals(R.drawable.icon2, si.getIconResourceId());
- // check another
- si = getCallerShortcut("ms2");
+ assertEquals(R.string.shortcut_title2, si.getTitleResId());
+ assertEquals("r" + R.string.shortcut_title2, si.getTitleResName());
+ assertEquals(R.string.shortcut_text2, si.getTextResId());
+ assertEquals("r" + R.string.shortcut_text2, si.getTextResName());
+ assertEquals(R.string.shortcut_disabled_message2,
+ si.getDisabledMessageResourceId());
+ assertEquals("r" + R.string.shortcut_disabled_message2,
+ si.getDisabledMessageResName());
- assertEquals("ms2", si.getId());
- assertEquals(R.drawable.icon2, si.getIconResourceId());
+ assertEquals(set("android.shortcut.conversation"), si.getCategories());
+ assertEquals("action2", si.getIntent().getAction());
+ assertEquals(null, si.getIntent().getData());
+ })
- assertEquals(R.string.shortcut_title2, si.getTitleResId());
- assertEquals("r" + R.string.shortcut_title2, si.getTitleResName());
- assertEquals(R.string.shortcut_text2, si.getTextResId());
- assertEquals("r" + R.string.shortcut_text2, si.getTextResName());
- assertEquals(R.string.shortcut_disabled_message2, si.getDisabledMessageResourceId());
- assertEquals("r" + R.string.shortcut_disabled_message2, si.getDisabledMessageResName());
+ .forShortcutWithId("ms3", si -> {
+ assertEquals(0, si.getIconResourceId());
+ assertEquals(R.string.shortcut_title1, si.getTitleResId());
+ assertEquals("r" + R.string.shortcut_title1, si.getTitleResName());
- assertEquals(set("android.shortcut.conversation"), si.getCategories());
- assertEquals("action2", si.getIntent().getAction());
- assertEquals(null, si.getIntent().getData());
+ assertEquals(0, si.getTextResId());
+ assertEquals(null, si.getTextResName());
+ assertEquals(0, si.getDisabledMessageResourceId());
+ assertEquals(null, si.getDisabledMessageResName());
- // check another
- si = getCallerShortcut("ms3");
+ assertEmpty(si.getCategories());
+ assertEquals("android.intent.action.VIEW", si.getIntent().getAction());
+ assertEquals(null, si.getIntent().getData());
+ })
- assertEquals("ms3", si.getId());
- assertEquals(0, si.getIconResourceId());
- assertEquals(R.string.shortcut_title1, si.getTitleResId());
- assertEquals("r" + R.string.shortcut_title1, si.getTitleResName());
+ .forShortcutWithId("ms4", si -> {
+ assertEquals(0, si.getIconResourceId());
+ assertEquals(R.string.shortcut_title2, si.getTitleResId());
+ assertEquals("r" + R.string.shortcut_title2, si.getTitleResName());
- assertEquals(0, si.getTextResId());
- assertEquals(null, si.getTextResName());
- assertEquals(0, si.getDisabledMessageResourceId());
- assertEquals(null, si.getDisabledMessageResName());
+ assertEquals(0, si.getTextResId());
+ assertEquals(null, si.getTextResName());
+ assertEquals(0, si.getDisabledMessageResourceId());
+ assertEquals(null, si.getDisabledMessageResName());
- assertEquals(null, si.getCategories());
- assertEquals("android.intent.action.VIEW", si.getIntent().getAction());
- assertEquals(null, si.getIntent().getData());
+ assertEquals(set("cat"), si.getCategories());
+ assertEquals("android.intent.action.VIEW2", si.getIntent().getAction());
+ assertEquals(null, si.getIntent().getData());
+ })
+
+ .forShortcutWithId("ms5", si -> {
+ si = getCallerShortcut("ms5");
+ assertEquals("action", si.getIntent().getAction());
+ assertEquals("http://www/", si.getIntent().getData().toString());
+ assertEquals("foo/bar", si.getIntent().getType());
+ assertEquals(
+ new ComponentName("abc", ".xyz"), si.getIntent().getComponent());
+
+ assertEquals(set("cat1", "cat2"), si.getIntent().getCategories());
+ assertEquals("value1", si.getIntent().getStringExtra("key1"));
+ assertEquals("value2", si.getIntent().getStringExtra("key2"));
+ });
});
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 8e32d6a..f570ff2 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -15,8 +15,11 @@
*/
package com.android.server.pm;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertBundlesEqual;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.makeBundle;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.parceled;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.set;
@@ -35,12 +38,14 @@
import android.content.res.Resources;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Icon;
+import android.net.Uri;
import android.os.PersistableBundle;
import android.os.UserHandle;
import android.test.MoreAsserts;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.frameworks.servicestests.R;
+import com.android.server.pm.ShortcutService.ConfigConstants;
/**
* Tests for ShortcutService and ShortcutManager.
@@ -67,18 +72,68 @@
"ID must be provided",
() -> new ShortcutInfo.Builder(getTestContext()).build());
- assertExpectException(NullPointerException.class, "Intent action must be set",
- () -> new ShortcutInfo.Builder(getTestContext()).setIntent(new Intent()));
-
- assertExpectException(NullPointerException.class, "Activity must be provided", () -> {
- ShortcutInfo si = new ShortcutInfo.Builder(getTestContext()).setId("id").build();
- assertTrue(getManager().setDynamicShortcuts(list(si)));
- });
+ assertExpectException(
+ RuntimeException.class,
+ "id cannot be empty",
+ () -> new ShortcutInfo.Builder(getTestContext(), null));
assertExpectException(
+ RuntimeException.class,
+ "id cannot be empty",
+ () -> new ShortcutInfo.Builder(getTestContext(), ""));
+
+ assertExpectException(
+ RuntimeException.class,
+ "intent cannot be null",
+ () -> new ShortcutInfo.Builder(getTestContext(), "id").setIntent(null));
+
+ assertExpectException(
+ RuntimeException.class,
+ "action must be set",
+ () -> new ShortcutInfo.Builder(getTestContext(), "id").setIntent(new Intent()));
+
+ assertExpectException(
+ RuntimeException.class,
+ "activity cannot be null",
+ () -> new ShortcutInfo.Builder(getTestContext(), "id").setActivity(null));
+
+ assertExpectException(
+ RuntimeException.class,
+ "shortLabel cannot be empty",
+ () -> new ShortcutInfo.Builder(getTestContext(), "id").setShortLabel(null));
+
+ assertExpectException(
+ RuntimeException.class,
+ "shortLabel cannot be empty",
+ () -> new ShortcutInfo.Builder(getTestContext(), "id").setShortLabel(""));
+
+ assertExpectException(
+ RuntimeException.class,
+ "longLabel cannot be empty",
+ () -> new ShortcutInfo.Builder(getTestContext(), "id").setLongLabel(null));
+
+ assertExpectException(
+ RuntimeException.class,
+ "longLabel cannot be empty",
+ () -> new ShortcutInfo.Builder(getTestContext(), "id").setLongLabel(""));
+
+ assertExpectException(
+ RuntimeException.class,
+ "disabledMessage cannot be empty",
+ () -> new ShortcutInfo.Builder(getTestContext(), "id").setDisabledMessage(null));
+
+ assertExpectException(
+ RuntimeException.class,
+ "disabledMessage cannot be empty",
+ () -> new ShortcutInfo.Builder(getTestContext(), "id").setDisabledMessage(""));
+
+ assertExpectException(NullPointerException.class, "action must be set",
+ () -> new ShortcutInfo.Builder(getTestContext(), "id").setIntent(new Intent()));
+
+ // same for add.
+ assertExpectException(
IllegalArgumentException.class, "Short label must be provided", () -> {
- ShortcutInfo si = new ShortcutInfo.Builder(getTestContext())
- .setId("id")
+ ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
.setActivity(new ComponentName(getTestContext().getPackageName(), "s"))
.build();
assertTrue(getManager().setDynamicShortcuts(list(si)));
@@ -86,25 +141,24 @@
assertExpectException(
IllegalArgumentException.class, "Short label must be provided", () -> {
- ShortcutInfo si = new ShortcutInfo.Builder(getTestContext())
- .setId("id")
+ ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
.setActivity(new ComponentName(getTestContext().getPackageName(), "s"))
.build();
assertTrue(getManager().addDynamicShortcuts(list(si)));
});
+ // same for add.
assertExpectException(NullPointerException.class, "Intent must be provided", () -> {
- ShortcutInfo si = new ShortcutInfo.Builder(getTestContext())
- .setId("id")
+ ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
.setActivity(new ComponentName(getTestContext().getPackageName(), "s"))
.setShortLabel("x")
.build();
assertTrue(getManager().setDynamicShortcuts(list(si)));
});
+ // same for add.
assertExpectException(NullPointerException.class, "Intent must be provided", () -> {
- ShortcutInfo si = new ShortcutInfo.Builder(getTestContext())
- .setId("id")
+ ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
.setActivity(new ComponentName(getTestContext().getPackageName(), "s"))
.setShortLabel("x")
.build();
@@ -112,18 +166,17 @@
});
assertExpectException(
- IllegalStateException.class, "package name mismatch", () -> {
- ShortcutInfo si = new ShortcutInfo.Builder(getTestContext())
- .setId("id")
+ IllegalStateException.class, "does not belong to package", () -> {
+ ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
.setActivity(new ComponentName("xxx", "s"))
.build();
assertTrue(getManager().setDynamicShortcuts(list(si)));
});
+ // same for add.
assertExpectException(
- IllegalStateException.class, "package name mismatch", () -> {
- ShortcutInfo si = new ShortcutInfo.Builder(getTestContext())
- .setId("id")
+ IllegalStateException.class, "does not belong to package", () -> {
+ ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
.setActivity(new ComponentName("xxx", "s"))
.build();
assertTrue(getManager().addDynamicShortcuts(list(si)));
@@ -329,7 +382,7 @@
assertEquals(mClientContext.getPackageName(), si.getPackage());
assertEquals("id", si.getId());
- assertEquals(null, si.getActivity());
+ assertEquals(new ComponentName("a", "b"), si.getActivity());
assertEquals(null, si.getIcon());
assertEquals(null, si.getTitle());
assertEquals(null, si.getText());
@@ -445,7 +498,7 @@
assertEquals(mClientContext.getPackageName(), si.getPackage());
assertEquals("id", si.getId());
- assertEquals(null, si.getActivity());
+ assertEquals(new ComponentName("a", "b"), si.getActivity());
assertEquals(null, si.getIcon());
assertEquals(0, si.getTitleResId());
assertEquals(null, si.getTitleResName());
@@ -777,6 +830,7 @@
.setRank(123)
.setExtras(pb)
.build();
+ sorig.setTimestamp(mInjectedCurrentTimeMillis);
ShortcutInfo sorig2 = new ShortcutInfo.Builder(mClientContext)
.setId("id2")
@@ -785,11 +839,13 @@
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setRank(456)
.build();
+ sorig2.setTimestamp(mInjectedCurrentTimeMillis);
mManager.addDynamicShortcuts(list(sorig, sorig2));
- Thread.sleep(2);
- final long now = System.currentTimeMillis();
+ mInjectedCurrentTimeMillis += 1;
+ final long now = mInjectedCurrentTimeMillis;
+ mInjectedCurrentTimeMillis += 1;
// Save and load.
mService.saveDirtyInfo();
@@ -845,6 +901,7 @@
.setRank(123)
.setExtras(pb)
.build();
+ sorig.setTimestamp(mInjectedCurrentTimeMillis);
ShortcutInfo sorig2 = new ShortcutInfo.Builder(mClientContext)
.setId("id2")
@@ -853,11 +910,13 @@
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setRank(456)
.build();
+ sorig2.setTimestamp(mInjectedCurrentTimeMillis);
mManager.addDynamicShortcuts(list(sorig, sorig2));
- Thread.sleep(2);
- final long now = System.currentTimeMillis();
+ mInjectedCurrentTimeMillis += 1;
+ final long now = mInjectedCurrentTimeMillis;
+ mInjectedCurrentTimeMillis += 1;
// Save and load.
mService.saveDirtyInfo();
@@ -1030,6 +1089,63 @@
assertEquals(0, si.getRank());
}
+ private void checkShortcutInfoSaveAndLoad_intents(Intent intent) {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcutWithIntent("s1", intent))));
+ initService();
+ mService.handleUnlockUser(USER_0);
+
+ assertWith(getCallerShortcuts())
+ .haveIds("s1")
+ .forShortcutWithId("s1", si -> {
+ assertEquals(intent.getAction(), si.getIntent().getAction());
+ assertEquals(intent.getData(), si.getIntent().getData());
+ assertEquals(intent.getComponent(), si.getIntent().getComponent());
+ assertBundlesEqual(intent.getExtras(), si.getExtras());
+ });
+ }
+
+ public void testShortcutInfoSaveAndLoad_intents() {
+ checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_VIEW));
+
+ mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
+
+ checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_MAIN));
+
+ mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
+
+ checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_VIEW,
+ Uri.parse("http://www.example.com/")));
+
+ mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
+
+ checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_MAIN,
+ Uri.parse("http://www.example.com/")));
+
+ mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
+
+ checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_VIEW)
+ .setComponent(new ComponentName("a", "b")));
+
+ mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
+
+ checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_MAIN)
+ .setComponent(new ComponentName("a", "b")));
+
+ mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
+
+ checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_VIEW)
+ .putExtras(makeBundle("a", "b")));
+
+ mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
+
+
+ checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_MAIN)
+ .putExtras(makeBundle("a", "b")));
+
+ mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
+ }
+
public void testThrottling() {
final ShortcutInfo si1 = makeShortcut("shortcut1");
@@ -1488,7 +1604,7 @@
// Simulate a call from sys UI.
mCallerPermissions.add(permission.RESET_SHORTCUT_MANAGER_THROTTLING);
- mService.onApplicationActive(CALLING_PACKAGE_1, USER_0);
+ mManager.onApplicationActive(CALLING_PACKAGE_1, USER_0);
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertEquals(3, mManager.getRemainingCallCount());
@@ -1509,7 +1625,7 @@
MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
});
- mService.onApplicationActive(CALLING_PACKAGE_3, USER_0);
+ mManager.onApplicationActive(CALLING_PACKAGE_3, USER_0);
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertEquals(3, mManager.getRemainingCallCount());
@@ -1530,7 +1646,7 @@
MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
});
- mService.onApplicationActive(CALLING_PACKAGE_1, USER_10);
+ mManager.onApplicationActive(CALLING_PACKAGE_1, USER_10);
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertEquals(3, mManager.getRemainingCallCount());
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java
new file mode 100644
index 0000000..a36c0ad
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java
@@ -0,0 +1,124 @@
+/*
+ * 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 static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertBundlesEqual;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.makeBundle;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.makePersistableBundle;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.PersistableBundle;
+
+public class ShortcutManagerTest4 extends BaseShortcutManagerTest {
+
+ private static Bundle sIntentExtras = makeBundle(
+ "key{\u0000}", "value{\u0000}",
+ "key{\u0001}", "value{\u0001}",
+ "key{\u001f}", "value{\u001f}",
+ "key{\u007f}", "value{\u007f}",
+
+ "key{\ud800\udc00}", "value{\ud800\udc00}",
+ "key{\ud801\udc01}", "value{\ud801\udc01}",
+ "key{\udbff\udfff}", "value{\udbff\udfff}",
+
+ "key{\ud801}x", 1, // broken surrogate pair
+ "key{\uDC01}\"x", 2, // broken surrogate pair
+
+ "x1", "value{\ud801}x", // broken surrogate pair
+ "x2", "value{\uDC01}\"x" // broken surrogate pair
+ );
+
+ // Same as above, except broken surrogate pairs are replaced with '?'s.
+ private static Bundle sIntentExtrasDecoded = makeBundle(
+ "key{\u0000}", "value{\u0000}",
+ "key{\u0001}", "value{\u0001}",
+ "key{\u001f}", "value{\u001f}",
+ "key{\u007f}", "value{\u007f}",
+
+ "key{\ud800\udc00}", "value{\ud800\udc00}",
+ "key{\ud801\udc01}", "value{\ud801\udc01}",
+ "key{\udbff\udfff}", "value{\udbff\udfff}",
+
+ "key{?}x", 1,
+ "key{?}\"x", 2,
+
+ "x1", "value{?}x",
+ "x2", "value{?}\"x"
+ );
+
+ private static PersistableBundle sShortcutExtras = makePersistableBundle(
+ "key{\u0000}", "value{\u0000}",
+ "key{\u0001}", "value{\u0001}",
+ "key{\u001f}", "value{\u001f}",
+ "key{\u007f}", "value{\u007f}",
+
+ "key{\ud800\udc00}", "value{\ud800\udc00}",
+ "key{\ud801\udc01}", "value{\ud801\udc01}",
+ "key{\udbff\udfff}", "value{\udbff\udfff}",
+
+ "key{\ud801}", 1, // broken surrogate pair
+ "key{\uDC01}", 2, // broken surrogate pair
+
+ "x1", "value{\ud801}", // broken surrogate pair
+ "x2", "value{\uDC01}" // broken surrogate pair
+ );
+
+ // Same as above, except broken surrogate pairs are replaced with '?'s.
+ private static PersistableBundle sShortcutExtrasDecoded = makePersistableBundle(
+ "key{\u0000}", "value{\u0000}",
+ "key{\u0001}", "value{\u0001}",
+ "key{\u001f}", "value{\u001f}",
+ "key{\u007f}", "value{\u007f}",
+
+ "key{\ud800\udc00}", "value{\ud800\udc00}",
+ "key{\ud801\udc01}", "value{\ud801\udc01}",
+ "key{\udbff\udfff}", "value{\udbff\udfff}",
+
+ "key{?}", 1,
+ "key{?}", 2,
+
+ "x1", "value{?}",
+ "x2", "value{?}"
+ );
+
+ public void testPersistingWeirdCharacters() {
+ final Intent intent = new Intent(Intent.ACTION_VIEW)
+ .putExtras(sIntentExtras);
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcutWithExtras("s1", intent, sShortcutExtras),
+ makeShortcut("s{\u0000}{\u0001}{\uD800\uDC00}x[\uD801][\uDC01]")
+ )));
+ });
+
+ // Make sure save & load works fine. (i.e. shouldn't crash even with invalid characters.)
+ initService();
+ mService.handleUnlockUser(USER_0);
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("s1", "s{\u0000}{\u0001}{\uD800\uDC00}x[?][?]")
+ .forShortcutWithId("s1", si -> {
+ assertBundlesEqual(si.getIntent().getExtras(), sIntentExtrasDecoded);
+ assertBundlesEqual(si.getExtras(), sShortcutExtrasDecoded);
+ });
+ });
+ }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
index c03324a..b737033 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
@@ -86,7 +86,7 @@
private void setEnabledAndValidPackageInfos(WebViewProviderInfo[] providers) {
for(WebViewProviderInfo wpi : providers) {
mTestSystemImpl.setPackageInfo(createPackageInfo(wpi.packageName, true /* enabled */,
- true /* valid */));
+ true /* valid */, true /* installed */));
}
}
@@ -137,12 +137,17 @@
}
private static PackageInfo createPackageInfo(
- String packageName, boolean enabled, boolean valid) {
+ String packageName, boolean enabled, boolean valid, boolean installed) {
PackageInfo p = new PackageInfo();
p.packageName = packageName;
p.applicationInfo = new ApplicationInfo();
p.applicationInfo.enabled = enabled;
p.applicationInfo.metaData = new Bundle();
+ if (installed) {
+ p.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
+ } else {
+ p.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
+ }
if (valid) {
// no flag means invalid
p.applicationInfo.metaData.putString(WEBVIEW_LIBRARY_FLAG, "blah");
@@ -150,10 +155,23 @@
return p;
}
- private static PackageInfo createPackageInfo(
- String packageName, boolean enabled, boolean valid, Signature[] signatures) {
- PackageInfo p = createPackageInfo(packageName, enabled, valid);
+ private static PackageInfo createPackageInfo(String packageName, boolean enabled, boolean valid,
+ boolean installed, Signature[] signatures, long updateTime) {
+ PackageInfo p = createPackageInfo(packageName, enabled, valid, installed);
p.signatures = signatures;
+ p.lastUpdateTime = updateTime;
+ return p;
+ }
+
+ private static PackageInfo createPackageInfo(String packageName, boolean enabled, boolean valid,
+ boolean installed, Signature[] signatures, long updateTime, boolean hidden) {
+ PackageInfo p =
+ createPackageInfo(packageName, enabled, valid, installed, signatures, updateTime);
+ if (hidden) {
+ p.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
+ } else {
+ p.applicationInfo.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN;
+ }
return p;
}
@@ -223,9 +241,11 @@
setupWithPackages(packages, true /* fallback logic enabled */, 1 /* numRelros */,
false /* isDebuggable */);
mTestSystemImpl.setPackageInfo(createPackageInfo(invalidPackage, true /* enabled */,
- true /* valid */, new Signature[]{invalidPackageSignature}));
+ true /* valid */, true /* installed */, new Signature[]{invalidPackageSignature}
+ , 0 /* updateTime */));
mTestSystemImpl.setPackageInfo(createPackageInfo(validPackage, true /* enabled */,
- true /* valid */, new Signature[]{validSignature}));
+ true /* valid */, true /* installed */, new Signature[]{validSignature}
+ , 0 /* updateTime */));
mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
@@ -273,7 +293,8 @@
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {wpi};
setupWithPackages(packages);
mTestSystemImpl.setPackageInfo(
- createPackageInfo(wpi.packageName, true /* enabled */, false /* valid */));
+ createPackageInfo(wpi.packageName, true /* enabled */, false /* valid */,
+ true /* installed */));
mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
@@ -285,9 +306,10 @@
// Verify that we can recover from failing to list webview packages.
mTestSystemImpl.setPackageInfo(
- createPackageInfo(wpi.packageName, true /* enabled */, true /* valid */));
+ createPackageInfo(wpi.packageName, true /* enabled */, true /* valid */,
+ true /* installed */));
mWebViewUpdateServiceImpl.packageStateChanged(wpi.packageName,
- WebViewUpdateService.PACKAGE_ADDED_REPLACED);
+ WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
checkPreparationPhasesForPackage(wpi.packageName, 1);
}
@@ -345,7 +367,7 @@
// Have all packages be disabled so that we can change one to enabled later
for(WebViewProviderInfo wpi : packages) {
mTestSystemImpl.setPackageInfo(createPackageInfo(wpi.packageName,
- false /* enabled */, true /* valid */));
+ false /* enabled */, true /* valid */, true /* installed */));
}
}
@@ -371,7 +393,7 @@
}
}).start();
try {
- Thread.sleep(1000); // Let the new thread run / be blocked
+ Thread.sleep(500); // Let the new thread run / be blocked
} catch (InterruptedException e) {
}
@@ -380,9 +402,9 @@
} else {
// Switch provider by enabling the second one
mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
- true /* valid */));
+ true /* valid */, true /* installed */));
mWebViewUpdateServiceImpl.packageStateChanged(
- secondPackage, WebViewUpdateService.PACKAGE_CHANGED);
+ secondPackage, WebViewUpdateService.PACKAGE_CHANGED, 0);
}
mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
// first package done, should start on second
@@ -432,9 +454,9 @@
// Enable fallback package
mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */,
- true /* valid */));
+ true /* valid */, true /* installed */));
mWebViewUpdateServiceImpl.packageStateChanged(
- fallbackPackage, WebViewUpdateService.PACKAGE_CHANGED);
+ fallbackPackage, WebViewUpdateService.PACKAGE_CHANGED, 0);
if (fallbackLogicEnabled) {
// Check that we have now disabled the fallback package twice
@@ -463,7 +485,8 @@
fallbackPackage, "", true /* default available */, true /* fallback */, null)};
setupWithPackages(packages, true /* isFallbackLogicEnabled */);
mTestSystemImpl.setPackageInfo(
- createPackageInfo(fallbackPackage, true /* enabled */ , true /* valid */));
+ createPackageInfo(fallbackPackage, true /* enabled */ , true /* valid */,
+ true /* installed */));
mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers(
@@ -474,9 +497,10 @@
// Install primary package
mTestSystemImpl.setPackageInfo(
- createPackageInfo(primaryPackage, true /* enabled */ , true /* valid */));
+ createPackageInfo(primaryPackage, true /* enabled */ , true /* valid */,
+ true /* installed */));
mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
- WebViewUpdateService.PACKAGE_ADDED_REPLACED);
+ WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
// Verify fallback disabled, primary package used as provider, and fallback package killed
Mockito.verify(mTestSystemImpl).uninstallAndDisablePackageForAllUsers(
@@ -507,9 +531,10 @@
// Disable primary package and ensure fallback becomes enabled and used
mTestSystemImpl.setPackageInfo(
- createPackageInfo(primaryPackage, false /* enabled */, true /* valid */));
+ createPackageInfo(primaryPackage, false /* enabled */, true /* valid */,
+ true /* installed */));
mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
- WebViewUpdateService.PACKAGE_CHANGED);
+ WebViewUpdateService.PACKAGE_CHANGED, 0);
Mockito.verify(mTestSystemImpl).enablePackageForUser(
Mockito.eq(fallbackPackage), Mockito.eq(true) /* enable */,
@@ -520,9 +545,10 @@
// Again enable primary package and verify primary is used and fallback becomes disabled
mTestSystemImpl.setPackageInfo(
- createPackageInfo(primaryPackage, true /* enabled */, true /* valid */));
+ createPackageInfo(primaryPackage, true /* enabled */, true /* valid */,
+ true /* installed */));
mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
- WebViewUpdateService.PACKAGE_CHANGED);
+ WebViewUpdateService.PACKAGE_CHANGED, 0);
// Verify fallback is disabled a second time when primary package becomes enabled
Mockito.verify(mTestSystemImpl, Mockito.times(2)).enablePackageForUser(
@@ -593,9 +619,10 @@
// Make packages invalid to cause exception to be thrown
mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */,
- false /* valid */));
+ false /* valid */, true /* installed */, null /* signatures */,
+ 0 /* updateTime */));
mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
- false /* valid */));
+ false /* valid */, true /* installed */));
// This shouldn't throw an exception!
mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
@@ -605,10 +632,11 @@
// Now make a package valid again and verify that we can switch back to that
mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */,
- true /* valid */));
+ true /* valid */, true /* installed */, null /* signatures */,
+ 1 /* updateTime */ ));
mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
- WebViewUpdateService.PACKAGE_ADDED_REPLACED);
+ WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
// Ensure we use firstPackage
checkPreparationPhasesForPackage(firstPackage, 2 /* second preparation for this package */);
@@ -634,16 +662,16 @@
// Remove second package (invalidate it) and verify that first package is used
mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
- false /* valid */));
+ false /* valid */, true /* installed */));
mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
- WebViewUpdateService.PACKAGE_ADDED);
+ WebViewUpdateService.PACKAGE_ADDED, 0);
checkPreparationPhasesForPackage(firstPackage, 2 /* second time for this package */);
// Now make the second package valid again and verify that it is used again
mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
- true /* valid */));
+ true /* valid */, true /* installed */));
mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
- WebViewUpdateService.PACKAGE_ADDED);
+ WebViewUpdateService.PACKAGE_ADDED, 0);
checkPreparationPhasesForPackage(secondPackage, 2 /* second time for this package */);
}
@@ -663,7 +691,7 @@
setupWithPackages(packages);
// Only 'install' nonChosenPackage
mTestSystemImpl.setPackageInfo(
- createPackageInfo(nonChosenPackage, true /* enabled */, true /* valid */));
+ createPackageInfo(nonChosenPackage, true /* enabled */, true /* valid */, true /* installed */));
// Set user-chosen package
mTestSystemImpl.updateUserSetting(null, chosenPackage);
@@ -702,16 +730,16 @@
// Make both packages invalid so that we fail listing WebView packages
mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */,
- false /* valid */));
+ false /* valid */, true /* installed */));
mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
- false /* valid */));
+ false /* valid */, true /* installed */));
// Change package to hit the webview packages listing problem.
if (settingsChange) {
mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
} else {
mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
- WebViewUpdateService.PACKAGE_ADDED_REPLACED);
+ WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
}
WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
@@ -719,10 +747,10 @@
// Make second package valid and verify that we can load it again
mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
- true /* valid */));
+ true /* valid */, true /* installed */));
mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
- WebViewUpdateService.PACKAGE_ADDED_REPLACED);
+ WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
checkPreparationPhasesForPackage(secondPackage, 1);
@@ -749,13 +777,14 @@
// Replace or remove the current webview package
if (replaced) {
mTestSystemImpl.setPackageInfo(
- createPackageInfo(firstPackage, true /* enabled */, false /* valid */));
+ createPackageInfo(firstPackage, true /* enabled */, false /* valid */,
+ true /* installed */));
mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
- WebViewUpdateService.PACKAGE_ADDED_REPLACED);
+ WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
} else {
mTestSystemImpl.removePackageInfo(firstPackage);
mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
- WebViewUpdateService.PACKAGE_REMOVED);
+ WebViewUpdateService.PACKAGE_REMOVED, 0);
}
checkPreparationPhasesForPackage(secondPackage, 1);
@@ -806,7 +835,7 @@
checkPreparationPhasesForPackage(thirdPackage, 1);
mTestSystemImpl.setPackageInfo(
- createPackageInfo(secondPackage, true /* enabled */, false /* valid */));
+ createPackageInfo(secondPackage, true /* enabled */, false /* valid */, true /* installed */));
// Try to switch to the invalid second package, this should result in switching to the first
// package, since that is more preferred than the third one.
@@ -817,4 +846,229 @@
Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(thirdPackage));
}
+
+ // Ensure that the update service uses an uninstalled package if that is the only package
+ // available.
+ public void testWithSingleUninstalledPackage() {
+ String testPackageName = "test.package.name";
+ WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] {
+ new WebViewProviderInfo(testPackageName, "",
+ true /*default available*/, false /* fallback */, null)};
+ setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */);
+ mTestSystemImpl.setPackageInfo(createPackageInfo(testPackageName, true /* enabled */,
+ true /* valid */, false /* installed */));
+
+ mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+
+ checkPreparationPhasesForPackage(testPackageName, 1 /* first preparation phase */);
+ }
+
+ public void testNonhiddenPackageUserOverHidden() {
+ checkVisiblePackageUserOverNonVisible(false /* true == uninstalled, false == hidden */);
+ }
+
+ public void testInstalledPackageUsedOverUninstalled() {
+ checkVisiblePackageUserOverNonVisible(true /* true == uninstalled, false == hidden */);
+ }
+
+ private void checkVisiblePackageUserOverNonVisible(boolean uninstalledNotHidden) {
+ boolean testUninstalled = uninstalledNotHidden;
+ boolean testHidden = !uninstalledNotHidden;
+ String installedPackage = "installedPackage";
+ String uninstalledPackage = "uninstalledPackage";
+ WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] {
+ new WebViewProviderInfo(uninstalledPackage, "", true /* available by default */,
+ false /* fallback */, null),
+ new WebViewProviderInfo(installedPackage, "", true /* available by default */,
+ false /* fallback */, null)};
+
+ setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */);
+ mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */,
+ true /* valid */, true /* installed */));
+ mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */,
+ true /* valid */, (testUninstalled ? false : true) /* installed */,
+ null /* signatures */, 0 /* updateTime */, (testHidden ? true : false)));
+
+ mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+
+ checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */);
+ }
+
+ public void testCantSwitchToHiddenPackage () {
+ checkCantSwitchToNonVisiblePackage(false /* true == uninstalled, false == hidden */);
+ }
+
+
+ public void testCantSwitchToUninstalledPackage () {
+ checkCantSwitchToNonVisiblePackage(true /* true == uninstalled, false == hidden */);
+ }
+
+ /**
+ * Ensure that we won't prioritize an uninstalled (or hidden) package even if it is user-chosen,
+ * and that an uninstalled (or hidden) package is not considered valid (in the
+ * getValidWebViewPackages() API).
+ */
+ private void checkCantSwitchToNonVisiblePackage(boolean uninstalledNotHidden) {
+ boolean testUninstalled = uninstalledNotHidden;
+ boolean testHidden = !uninstalledNotHidden;
+ String installedPackage = "installedPackage";
+ String uninstalledPackage = "uninstalledPackage";
+ WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] {
+ new WebViewProviderInfo(uninstalledPackage, "", true /* available by default */,
+ false /* fallback */, null),
+ new WebViewProviderInfo(installedPackage, "", true /* available by default */,
+ false /* fallback */, null)};
+
+ setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */);
+ mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */,
+ true /* valid */, true /* installed */));
+ mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */,
+ true /* valid */, (testUninstalled ? false : true) /* installed */,
+ null /* signatures */, 0 /* updateTime */,
+ (testHidden ? true : false) /* hidden */));
+
+ mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+
+ checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */);
+
+ // Ensure that only the installed package is considered valid
+ WebViewProviderInfo[] validPackages = mWebViewUpdateServiceImpl.getValidWebViewPackages();
+ assertEquals(1, validPackages.length);
+ assertEquals(installedPackage, validPackages[0].packageName);
+
+ // ensure that we don't switch to the uninstalled package (it will be used if it becomes
+ // installed later)
+ assertEquals(installedPackage,
+ mWebViewUpdateServiceImpl.changeProviderAndSetting(uninstalledPackage));
+
+ // We should only have called onWebViewProviderChanged once (before calling
+ // changeProviderAndSetting
+ Mockito.verify(mTestSystemImpl, Mockito.times(1)).onWebViewProviderChanged(
+ Mockito.argThat(new IsPackageInfoWithName(installedPackage)));
+ }
+
+ public void testHiddenPackageNotPrioritizedEvenIfChosen() {
+ checkNonvisiblePackageNotPrioritizedEvenIfChosen(
+ false /* true == uninstalled, false == hidden */);
+ }
+
+ public void testUninstalledPackageNotPrioritizedEvenIfChosen() {
+ checkNonvisiblePackageNotPrioritizedEvenIfChosen(
+ true /* true == uninstalled, false == hidden */);
+ }
+
+ public void checkNonvisiblePackageNotPrioritizedEvenIfChosen(boolean uninstalledNotHidden) {
+ boolean testUninstalled = uninstalledNotHidden;
+ boolean testHidden = !uninstalledNotHidden;
+ String installedPackage = "installedPackage";
+ String uninstalledPackage = "uninstalledPackage";
+ WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] {
+ new WebViewProviderInfo(uninstalledPackage, "", true /* available by default */,
+ false /* fallback */, null),
+ new WebViewProviderInfo(installedPackage, "", true /* available by default */,
+ false /* fallback */, null)};
+
+ setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */);
+ mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */,
+ true /* valid */, true /* installed */));
+ mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */,
+ true /* valid */, (testUninstalled ? false : true) /* installed */,
+ null /* signatures */, 0 /* updateTime */,
+ (testHidden ? true : false) /* hidden */));
+
+ // Start with the setting pointing to the uninstalled package
+ mTestSystemImpl.updateUserSetting(null, uninstalledPackage);
+
+ mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+
+ checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */);
+ }
+
+ /**
+ * Ensures that fallback becomes enabled if the primary package is uninstalled for the current
+ * user.
+ */
+ public void testFallbackEnabledIfPrimaryUninstalled() {
+ String primaryPackage = "primary";
+ String fallbackPackage = "fallback";
+ WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
+ new WebViewProviderInfo(
+ primaryPackage, "", true /* default available */, false /* fallback */, null),
+ new WebViewProviderInfo(
+ fallbackPackage, "", true /* default available */, true /* fallback */, null)};
+ setupWithPackages(packages, true /* fallback logic enabled */);
+ mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
+ true /* valid */, false /* installed */));
+ mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */,
+ true /* valid */, true /* installed */));
+
+ mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+ // Verify that we enable the fallback package
+ Mockito.verify(mTestSystemImpl).enablePackageForAllUsers(
+ Mockito.anyObject(), Mockito.eq(fallbackPackage), Mockito.eq(true) /* enable */);
+
+ checkPreparationPhasesForPackage(fallbackPackage, 1 /* first preparation phase */);
+ }
+
+ public void testPreparationRunsIffNewPackage() {
+ String primaryPackage = "primary";
+ String fallbackPackage = "fallback";
+ WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
+ new WebViewProviderInfo(
+ primaryPackage, "", true /* default available */, false /* fallback */, null),
+ new WebViewProviderInfo(
+ fallbackPackage, "", true /* default available */, true /* fallback */, null)};
+ setupWithPackages(packages, true /* fallback logic enabled */);
+ mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
+ true /* valid */, true /* installed */, null /* signatures */,
+ 10 /* lastUpdateTime*/ ));
+ mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */,
+ true /* valid */, true /* installed */));
+
+ mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+
+ checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation phase */);
+ Mockito.verify(mTestSystemImpl, Mockito.times(1)).enablePackageForUser(
+ Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
+ Matchers.anyInt() /* user */);
+
+
+ mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
+ WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0 /* userId */);
+ mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
+ WebViewUpdateService.PACKAGE_ADDED_REPLACED, 1 /* userId */);
+ mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
+ WebViewUpdateService.PACKAGE_ADDED_REPLACED, 2 /* userId */);
+ // package still has the same update-time so we shouldn't run preparation here
+ Mockito.verify(mTestSystemImpl, Mockito.times(1)).onWebViewProviderChanged(
+ Mockito.argThat(new IsPackageInfoWithName(primaryPackage)));
+ Mockito.verify(mTestSystemImpl, Mockito.times(1)).enablePackageForUser(
+ Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
+ Matchers.anyInt() /* user */);
+
+ // Ensure we can still load the package
+ WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
+ assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
+ assertEquals(primaryPackage, response.packageInfo.packageName);
+
+
+ mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
+ true /* valid */, true /* installed */, null /* signatures */,
+ 20 /* lastUpdateTime*/ ));
+ mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
+ WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
+ // The package has now changed - ensure that we have run the preparation phase a second time
+ checkPreparationPhasesForPackage(primaryPackage, 2 /* second preparation phase */);
+
+
+ mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
+ true /* valid */, true /* installed */, null /* signatures */,
+ 50 /* lastUpdateTime*/ ));
+ // Receive intent for different user
+ mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
+ WebViewUpdateService.PACKAGE_ADDED_REPLACED, 2);
+
+ checkPreparationPhasesForPackage(primaryPackage, 3 /* third preparation phase */);
+ }
+
}
diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
index 7ba4c68..7d7285a 100644
--- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
+++ b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
@@ -18,14 +18,17 @@
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNotSame;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
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.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -34,22 +37,29 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.LauncherApps;
+import android.content.pm.LauncherApps.Callback;
import android.content.pm.ShortcutInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.BaseBundle;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
import android.os.UserHandle;
import android.test.MoreAsserts;
+import android.util.ArraySet;
import android.util.Log;
import junit.framework.Assert;
+import junit.framework.AssertionFailedError;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import java.io.BufferedReader;
@@ -65,7 +75,9 @@
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
+import java.util.concurrent.CountDownLatch;
import java.util.function.BooleanSupplier;
+import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -163,7 +175,8 @@
}
public static void setDefaultLauncher(Instrumentation instrumentation, String component) {
- runCommandForNoOutput(instrumentation, "cmd package set-home-activity " + component);
+ runCommand(instrumentation, "cmd package set-home-activity " + component,
+ result -> result.contains("Success"));
}
public static void setDefaultLauncher(Instrumentation instrumentation, Context packageContext) {
@@ -197,6 +210,7 @@
if (!ENABLE_DUMPSYS) {
return;
}
+ Log.e(TAG, "Dumpsys shortcut");
for (String s : runCommand(instrumentation, "dumpsys shortcut")) {
Log.e(TAG, s);
}
@@ -229,6 +243,33 @@
return ret;
}
+ public static PersistableBundle makePersistableBundle(Object... keysAndValues) {
+ assertTrue((keysAndValues.length % 2) == 0);
+
+ if (keysAndValues.length == 0) {
+ return null;
+ }
+ final PersistableBundle ret = new PersistableBundle();
+
+ for (int i = keysAndValues.length - 2; i >= 0; i -= 2) {
+ final String key = keysAndValues[i].toString();
+ final Object value = keysAndValues[i + 1];
+
+ if (value == null) {
+ ret.putString(key, null);
+ } else if (value instanceof Integer) {
+ ret.putInt(key, (Integer) value);
+ } else if (value instanceof String) {
+ ret.putString(key, (String) value);
+ } else if (value instanceof PersistableBundle) {
+ ret.putPersistableBundle(key, (PersistableBundle) value);
+ } else {
+ fail("Type not supported yet: " + value.getClass().getName());
+ }
+ }
+ return ret;
+ }
+
public static <T> List<T> list(T... array) {
return Arrays.asList(array);
}
@@ -259,9 +300,12 @@
}
}
- public static <T> List<T> assertEmpty(List<T> list) {
- assertEquals(0, list.size());
- return list;
+ public static <T extends Collection<?>> T assertEmpty(T collection) {
+ if (collection == null) {
+ return collection; // okay.
+ }
+ assertEquals(0, collection.size());
+ return collection;
}
public static List<ShortcutInfo> filter(List<ShortcutInfo> list, Predicate<ShortcutInfo> p) {
@@ -274,7 +318,7 @@
ComponentName activity) {
return filter(list, si ->
(si.getActivity().equals(activity)
- && (si.isManifestShortcut() || si.isDynamic())));
+ && (si.isDeclaredInManifest() || si.isDynamic())));
}
public static List<ShortcutInfo> changedSince(List<ShortcutInfo> list, long time) {
@@ -371,32 +415,6 @@
return actualShortcuts;
}
- public static List<ShortcutInfo> assertAllHaveIconResId(
- List<ShortcutInfo> actualShortcuts) {
- for (ShortcutInfo s : actualShortcuts) {
- assertTrue("ID " + s.getId() + " not have icon res ID", s.hasIconResource());
- assertFalse("ID " + s.getId() + " shouldn't have icon FD", s.hasIconFile());
- }
- return actualShortcuts;
- }
-
- public static List<ShortcutInfo> assertAllHaveIconFile(
- List<ShortcutInfo> actualShortcuts) {
- for (ShortcutInfo s : actualShortcuts) {
- assertFalse("ID " + s.getId() + " shouldn't have icon res ID", s.hasIconResource());
- assertTrue("ID " + s.getId() + " not have icon FD", s.hasIconFile());
- }
- return actualShortcuts;
- }
-
- public static List<ShortcutInfo> assertAllHaveIcon(
- List<ShortcutInfo> actualShortcuts) {
- for (ShortcutInfo s : actualShortcuts) {
- assertTrue("ID " + s.getId() + " has no icon ", s.hasIconFile() || s.hasIconResource());
- }
- return actualShortcuts;
- }
-
public static List<ShortcutInfo> assertAllKeyFieldsOnly(
List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
@@ -438,7 +456,7 @@
public static List<ShortcutInfo> assertAllManifest(
List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
- assertTrue("ID " + s.getId(), s.isManifestShortcut());
+ assertTrue("ID " + s.getId(), s.isDeclaredInManifest());
}
return actualShortcuts;
}
@@ -446,7 +464,7 @@
public static List<ShortcutInfo> assertAllNotManifest(
List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
- assertFalse("ID " + s.getId(), s.isManifestShortcut());
+ assertFalse("ID " + s.getId(), s.isDeclaredInManifest());
}
return actualShortcuts;
}
@@ -475,14 +493,6 @@
return actualShortcuts;
}
- public static List<ShortcutInfo> assertAllStringsResolved(
- List<ShortcutInfo> actualShortcuts) {
- for (ShortcutInfo s : actualShortcuts) {
- assertTrue("ID " + s.getId(), s.hasStringResourcesResolved());
- }
- return actualShortcuts;
- }
-
public static void assertDynamicOnly(ShortcutInfo si) {
assertTrue(si.isDynamic());
assertFalse(si.isPinned());
@@ -490,7 +500,7 @@
public static void assertPinnedOnly(ShortcutInfo si) {
assertFalse(si.isDynamic());
- assertFalse(si.isManifestShortcut());
+ assertFalse(si.isDeclaredInManifest());
assertTrue(si.isPinned());
}
@@ -653,42 +663,73 @@
* New style assertion that allows chained calls.
*/
public static class ShortcutListAsserter {
+ private final ShortcutListAsserter mOriginal;
private final List<ShortcutInfo> mList;
ShortcutListAsserter(List<ShortcutInfo> list) {
- mList = new ArrayList<>(list);
+ this(null, list);
+ }
+
+ private ShortcutListAsserter(ShortcutListAsserter original, List<ShortcutInfo> list) {
+ mOriginal = (original == null) ? this : original;
+ mList = (list == null) ? new ArrayList<>(0) : new ArrayList<>(list);
+ }
+
+ public ShortcutListAsserter revertToOriginalList() {
+ return mOriginal;
}
public ShortcutListAsserter selectDynamic() {
- return new ShortcutListAsserter(
+ return new ShortcutListAsserter(this,
filter(mList, ShortcutInfo::isDynamic));
}
public ShortcutListAsserter selectManifest() {
- return new ShortcutListAsserter(
- filter(mList, ShortcutInfo::isManifestShortcut));
+ return new ShortcutListAsserter(this,
+ filter(mList, ShortcutInfo::isDeclaredInManifest));
}
public ShortcutListAsserter selectPinned() {
- return new ShortcutListAsserter(
+ return new ShortcutListAsserter(this,
filter(mList, ShortcutInfo::isPinned));
}
public ShortcutListAsserter selectByActivity(ComponentName activity) {
- return new ShortcutListAsserter(
+ return new ShortcutListAsserter(this,
ShortcutManagerTestUtils.filterByActivity(mList, activity));
}
public ShortcutListAsserter selectByChangedSince(long time) {
- return new ShortcutListAsserter(
+ return new ShortcutListAsserter(this,
ShortcutManagerTestUtils.changedSince(mList, time));
}
+ public ShortcutListAsserter selectByIds(String... ids) {
+ final Set<String> idSet = set(ids);
+ final ArrayList<ShortcutInfo> selected = new ArrayList<>();
+ for (ShortcutInfo si : mList) {
+ if (idSet.contains(si.getId())) {
+ selected.add(si);
+ idSet.remove(si.getId());
+ }
+ }
+ if (idSet.size() > 0) {
+ fail("Shortcuts not found for IDs=" + idSet);
+ }
+
+ return new ShortcutListAsserter(this, selected);
+ }
+
public ShortcutListAsserter toSortByRank() {
- return new ShortcutListAsserter(
+ return new ShortcutListAsserter(this,
ShortcutManagerTestUtils.sortedByRank(mList));
}
+ public ShortcutListAsserter call(Consumer<List<ShortcutInfo>> c) {
+ c.accept(mList);
+ return this;
+ }
+
public ShortcutListAsserter haveIds(String... expectedIds) {
assertShortcutIds(mList, expectedIds);
return this;
@@ -701,7 +742,8 @@
private ShortcutListAsserter haveSequentialRanks() {
for (int i = 0; i < mList.size(); i++) {
- assertEquals("Rank not sequential", i, mList.get(i).getRank());
+ final ShortcutInfo si = mList.get(i);
+ assertEquals("Rank not sequential: id=" + si.getId(), i, si.getRank());
}
return this;
}
@@ -717,5 +759,224 @@
assertEquals(0, mList.size());
return this;
}
+
+ public ShortcutListAsserter areAllDynamic() {
+ forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.isDynamic()));
+ return this;
+ }
+
+ public ShortcutListAsserter areAllNotDynamic() {
+ forAllShortcuts(s -> assertFalse("id=" + s.getId(), s.isDynamic()));
+ return this;
+ }
+
+ public ShortcutListAsserter areAllPinned() {
+ forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.isPinned()));
+ return this;
+ }
+
+ public ShortcutListAsserter areAllNotPinned() {
+ forAllShortcuts(s -> assertFalse("id=" + s.getId(), s.isPinned()));
+ return this;
+ }
+
+ public ShortcutListAsserter areAllManifest() {
+ forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.isDeclaredInManifest()));
+ return this;
+ }
+
+ public ShortcutListAsserter areAllNotManifest() {
+ forAllShortcuts(s -> assertFalse("id=" + s.getId(), s.isDeclaredInManifest()));
+ return this;
+ }
+
+ public ShortcutListAsserter areAllImmutable() {
+ forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.isImmutable()));
+ return this;
+ }
+
+ public ShortcutListAsserter areAllMutable() {
+ forAllShortcuts(s -> assertFalse("id=" + s.getId(), s.isImmutable()));
+ return this;
+ }
+
+ public ShortcutListAsserter areAllEnabled() {
+ forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.isEnabled()));
+ return this;
+ }
+
+ public ShortcutListAsserter areAllDisabled() {
+ forAllShortcuts(s -> assertFalse("id=" + s.getId(), s.isEnabled()));
+ return this;
+ }
+
+ public ShortcutListAsserter areAllWithKeyFieldsOnly() {
+ forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.hasKeyFieldsOnly()));
+ return this;
+ }
+
+ public ShortcutListAsserter areAllNotWithKeyFieldsOnly() {
+ forAllShortcuts(s -> assertFalse("id=" + s.getId(), s.hasKeyFieldsOnly()));
+ return this;
+ }
+
+ public ShortcutListAsserter areAllWithActivity(ComponentName activity) {
+ forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.getActivity().equals(activity)));
+ return this;
+ }
+
+ public ShortcutListAsserter forAllShortcuts(Consumer<ShortcutInfo> sa) {
+ boolean found = false;
+ for (int i = 0; i < mList.size(); i++) {
+ final ShortcutInfo si = mList.get(i);
+ found = true;
+ sa.accept(si);
+ }
+ assertTrue("No shortcuts found.", found);
+ return this;
+ }
+
+ public ShortcutListAsserter forShortcut(Predicate<ShortcutInfo> p,
+ Consumer<ShortcutInfo> sa) {
+ boolean found = false;
+ for (int i = 0; i < mList.size(); i++) {
+ final ShortcutInfo si = mList.get(i);
+ if (p.test(si)) {
+ found = true;
+ try {
+ sa.accept(si);
+ } catch (Throwable e) {
+ throw new AssertionError("Assertion failed for shortcut " + si.getId(), e);
+ }
+ }
+ }
+ assertTrue("Shortcut with the given condition not found.", found);
+ return this;
+ }
+
+ public ShortcutListAsserter forShortcutWithId(String id, Consumer<ShortcutInfo> sa) {
+ forShortcut(si -> si.getId().equals(id), sa);
+
+ return this;
+ }
+ }
+
+ public static void assertBundlesEqual(BaseBundle b1, BaseBundle b2) {
+ if (b1 == null && b2 == null) {
+ return; // pass
+ }
+ assertNotNull(b1);
+ assertNotNull(b2);
+
+ // HashSet makes the error message readable.
+ assertEquals(set(b1.keySet()), set(b2.keySet()));
+
+ for (String key : b1.keySet()) {
+ final Object v1 = b1.get(key);
+ final Object v2 = b2.get(key);
+ if (v1 == null) {
+ if (v2 == null) {
+ return;
+ }
+ }
+ if (v1.equals(v2)) {
+ return;
+ }
+
+ assertTrue("Only either value is null: key=" + key
+ + " b1=" + b1 + " b2=" + b2, v1 != null && v2 != null);
+ assertEquals("Class mismatch: key=" + key, v1.getClass(), v2.getClass());
+
+ if (v1 instanceof BaseBundle) {
+ assertBundlesEqual((BaseBundle) v1, (BaseBundle) v2);
+
+ } else if (v1 instanceof boolean[]) {
+ assertTrue(Arrays.equals((boolean[]) v1, (boolean[]) v2));
+
+ } else if (v1 instanceof int[]) {
+ MoreAsserts.assertEquals((int[]) v1, (int[]) v2);
+
+ } else if (v1 instanceof double[]) {
+ MoreAsserts.assertEquals((double[]) v1, (double[]) v2);
+
+ } else if (v1 instanceof String[]) {
+ MoreAsserts.assertEquals((String[]) v1, (String[]) v2);
+
+ } else if (v1 instanceof Double) {
+ if (((Double) v1).isNaN()) {
+ assertTrue(((Double) v2).isNaN());
+ } else {
+ assertEquals(v1, v2);
+ }
+
+ } else {
+ assertEquals(v1, v2);
+ }
+ }
+ }
+
+ public static void waitOnMainThread() throws InterruptedException {
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ new Handler(Looper.getMainLooper()).post(() -> latch.countDown());
+
+ latch.await();
+ }
+
+ public static class LauncherCallbackAsserter {
+ private final LauncherApps.Callback mCallback = mock(LauncherApps.Callback.class);
+
+ private Callback getMockCallback() {
+ return mCallback;
+ }
+
+ public LauncherCallbackAsserter assertNoCallbackCalled() {
+ verify(mCallback, times(0)).onShortcutsChanged(
+ anyString(),
+ any(List.class),
+ any(UserHandle.class));
+ return this;
+ }
+
+ public LauncherCallbackAsserter assertNoCallbackCalledForPackage(
+ String publisherPackageName) {
+ verify(mCallback, times(0)).onShortcutsChanged(
+ eq(publisherPackageName),
+ any(List.class),
+ any(UserHandle.class));
+ return this;
+ }
+
+ public LauncherCallbackAsserter assertNoCallbackCalledForPackageAndUser(
+ String publisherPackageName, UserHandle publisherUserHandle) {
+ verify(mCallback, times(0)).onShortcutsChanged(
+ eq(publisherPackageName),
+ any(List.class),
+ eq(publisherUserHandle));
+ return this;
+ }
+
+ public ShortcutListAsserter assertCallbackCalledForPackageAndUser(
+ String publisherPackageName, UserHandle publisherUserHandle) {
+ final ArgumentCaptor<List> shortcuts = ArgumentCaptor.forClass(List.class);
+ verify(mCallback, times(1)).onShortcutsChanged(
+ eq(publisherPackageName),
+ shortcuts.capture(),
+ eq(publisherUserHandle));
+ return new ShortcutListAsserter(shortcuts.getValue());
+ }
+ }
+
+ public static LauncherCallbackAsserter assertForLauncherCallback(
+ LauncherApps launcherApps, Runnable body) throws InterruptedException {
+ final LauncherCallbackAsserter asserter = new LauncherCallbackAsserter();
+ launcherApps.registerCallback(asserter.getMockCallback(),
+ new Handler(Looper.getMainLooper()));
+
+ body.run();
+
+ waitOnMainThread();
+
+ return asserter;
}
}
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 5843fbb..3930208 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -367,6 +367,14 @@
public static final String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
/**
+ * Boolean connection extra key set on a {@link Connection} in
+ * {@link Connection#STATE_RINGING} state to indicate that answering the call will cause the
+ * current active foreground call to be dropped.
+ */
+ public static final String EXTRA_ANSWERING_DROPS_FG_CALL =
+ "android.telecom.extra.ANSWERING_DROPS_FG_CALL";
+
+ /**
* Connection event used to inform Telecom that it should play the on hold tone. This is used
* to play a tone when the peer puts the current call on hold. Sent to Telecom via
* {@link #sendConnectionEvent(String)}.
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 44d89c1..2458cc8 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -777,6 +777,37 @@
/** @hide */
public static final int CDMA_ROAMING_MODE_ANY = 2;
+ /**
+ * The families of Radio Access Technologies that will get clustered and ratcheted,
+ * ie, we will report transitions up within the family, but not down until we change
+ * cells. This prevents flapping between base technologies and higher techs that are
+ * granted on demand within the cell.
+ * @hide
+ */
+ public static final String KEY_RATCHET_RAT_FAMILIES =
+ "ratchet_rat_families";
+
+ /**
+ * Flag indicating whether some telephony logic will treat a call which was formerly a video
+ * call as if it is still a video call. When {@code true}:
+ * <p>
+ * Logic which will automatically drop a video call which takes place over WIFI when a
+ * voice call is answered (see {@link #KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL}.
+ * <p>
+ * Logic which determines whether the user can use TTY calling.
+ */
+ public static final String KEY_TREAT_DOWNGRADED_VIDEO_CALLS_AS_VIDEO_CALLS_BOOL =
+ "treat_downgraded_video_calls_as_video_calls_bool";
+
+ /**
+ * When {@code true}, if the user is in an ongoing video call over WIFI and answers an incoming
+ * audio call, the video call will be disconnected before the audio call is answered. This is
+ * in contrast to the usual expected behavior where a foreground video call would be put into
+ * the background and held when an incoming audio call is answered.
+ */
+ public static final String KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL =
+ "drop_video_call_when_answering_audio_call_bool";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -922,6 +953,14 @@
sDefaults.putStringArray(KEY_SIGNAL_DCFAILURE_RECEIVER_STRING_ARRAY, null);
sDefaults.putStringArray(KEY_SIGNAL_PCO_RECEIVER_STRING_ARRAY, null);
sDefaults.putString(KEY_CARRIER_SETUP_APP_STRING, "");
+
+ // Rat families: {GPRS, EDGE}, {EVDO, EVDO_A, EVDO_B}, {UMTS, HSPA, HSDPA, HSUPA, HSPAP},
+ // {LTE, LTE_CA}
+ // Order is important - lowest precidence first
+ sDefaults.putStringArray(KEY_RATCHET_RAT_FAMILIES,
+ new String[]{"1,2","7,8,12","3,11,9,10,15","14,19"});
+ sDefaults.putBoolean(KEY_TREAT_DOWNGRADED_VIDEO_CALLS_AS_VIDEO_CALLS_BOOL, true);
+ sDefaults.putBoolean(KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL, true);
}
/**
diff --git a/telephony/java/android/telephony/RadioAccessFamily.java b/telephony/java/android/telephony/RadioAccessFamily.java
index 2bfaf1b..b530a64 100644
--- a/telephony/java/android/telephony/RadioAccessFamily.java
+++ b/telephony/java/android/telephony/RadioAccessFamily.java
@@ -47,6 +47,7 @@
public static final int RAF_HSPAP = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP);
public static final int RAF_GSM = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_GSM);
public static final int RAF_TD_SCDMA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA);
+ public static final int RAF_LTE_CA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA);
// Grouping of RAFs
private static final int GSM = RAF_GSM | RAF_GPRS | RAF_EDGE;
@@ -54,6 +55,7 @@
private static final int CDMA = RAF_IS95A | RAF_IS95B | RAF_1xRTT;
private static final int EVDO = RAF_EVDO_0 | RAF_EVDO_A | RAF_EVDO_B | RAF_EHRPD;
private static final int WCDMA = HS | RAF_UMTS;
+ private static final int LTE = RAF_LTE | RAF_LTE_CA;
/* Phone ID of phone */
private int mPhoneId;
@@ -162,19 +164,19 @@
raf = CDMA | EVDO;
break;
case RILConstants.NETWORK_MODE_LTE_CDMA_EVDO:
- raf = RAF_LTE | CDMA | EVDO;
+ raf = LTE | CDMA | EVDO;
break;
case RILConstants.NETWORK_MODE_LTE_GSM_WCDMA:
- raf = RAF_LTE | GSM | WCDMA;
+ raf = LTE | GSM | WCDMA;
break;
case RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA:
- raf = RAF_LTE | CDMA | EVDO | GSM | WCDMA;
+ raf = LTE | CDMA | EVDO | GSM | WCDMA;
break;
case RILConstants.NETWORK_MODE_LTE_ONLY:
- raf = RAF_LTE;
+ raf = LTE;
break;
case RILConstants.NETWORK_MODE_LTE_WCDMA:
- raf = RAF_LTE | WCDMA;
+ raf = LTE | WCDMA;
break;
case RILConstants.NETWORK_MODE_CDMA_NO_EVDO:
raf = CDMA;
@@ -192,28 +194,28 @@
raf = RAF_TD_SCDMA | WCDMA;
break;
case RILConstants.NETWORK_MODE_LTE_TDSCDMA:
- raf = RAF_LTE | RAF_TD_SCDMA;
+ raf = LTE | RAF_TD_SCDMA;
break;
case RILConstants.NETWORK_MODE_TDSCDMA_GSM:
raf = RAF_TD_SCDMA | GSM;
break;
case RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM:
- raf = RAF_LTE | RAF_TD_SCDMA | GSM;
+ raf = LTE | RAF_TD_SCDMA | GSM;
break;
case RILConstants.NETWORK_MODE_TDSCDMA_GSM_WCDMA:
raf = RAF_TD_SCDMA | GSM | WCDMA;
break;
case RILConstants.NETWORK_MODE_LTE_TDSCDMA_WCDMA:
- raf = RAF_LTE | RAF_TD_SCDMA | WCDMA;
+ raf = LTE | RAF_TD_SCDMA | WCDMA;
break;
case RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA:
- raf = RAF_LTE | RAF_TD_SCDMA | GSM | WCDMA;
+ raf = LTE | RAF_TD_SCDMA | GSM | WCDMA;
break;
case RILConstants.NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA:
raf = RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA;
break;
case RILConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA:
- raf = RAF_LTE | RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA;
+ raf = LTE | RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA;
break;
default:
raf = RAF_UNKNOWN;
@@ -232,6 +234,7 @@
raf = ((WCDMA & raf) > 0) ? (WCDMA | raf) : raf;
raf = ((CDMA & raf) > 0) ? (CDMA | raf) : raf;
raf = ((EVDO & raf) > 0) ? (EVDO | raf) : raf;
+ raf = ((LTE & raf) > 0) ? (LTE | raf) : raf;
return raf;
}
@@ -254,19 +257,19 @@
case (CDMA | EVDO):
type = RILConstants.NETWORK_MODE_CDMA;
break;
- case (RAF_LTE | CDMA | EVDO):
+ case (LTE | CDMA | EVDO):
type = RILConstants.NETWORK_MODE_LTE_CDMA_EVDO;
break;
- case (RAF_LTE | GSM | WCDMA):
+ case (LTE | GSM | WCDMA):
type = RILConstants.NETWORK_MODE_LTE_GSM_WCDMA;
break;
- case (RAF_LTE | CDMA | EVDO | GSM | WCDMA):
+ case (LTE | CDMA | EVDO | GSM | WCDMA):
type = RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA;
break;
- case RAF_LTE:
+ case LTE:
type = RILConstants.NETWORK_MODE_LTE_ONLY;
break;
- case (RAF_LTE | WCDMA):
+ case (LTE | WCDMA):
type = RILConstants.NETWORK_MODE_LTE_WCDMA;
break;
case CDMA:
@@ -284,28 +287,28 @@
case (RAF_TD_SCDMA | WCDMA):
type = RILConstants.NETWORK_MODE_TDSCDMA_WCDMA;
break;
- case (RAF_LTE | RAF_TD_SCDMA):
+ case (LTE | RAF_TD_SCDMA):
type = RILConstants.NETWORK_MODE_LTE_TDSCDMA;
break;
case (RAF_TD_SCDMA | GSM):
type = RILConstants.NETWORK_MODE_TDSCDMA_GSM;
break;
- case (RAF_LTE | RAF_TD_SCDMA | GSM):
+ case (LTE | RAF_TD_SCDMA | GSM):
type = RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM;
break;
case (RAF_TD_SCDMA | GSM | WCDMA):
type = RILConstants.NETWORK_MODE_TDSCDMA_GSM_WCDMA;
break;
- case (RAF_LTE | RAF_TD_SCDMA | WCDMA):
+ case (LTE | RAF_TD_SCDMA | WCDMA):
type = RILConstants.NETWORK_MODE_LTE_TDSCDMA_WCDMA;
break;
- case (RAF_LTE | RAF_TD_SCDMA | GSM | WCDMA):
+ case (LTE | RAF_TD_SCDMA | GSM | WCDMA):
type = RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA;
break;
case (RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA):
type = RILConstants.NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA;
break;
- case (RAF_LTE | RAF_TD_SCDMA | RAF_LTE | CDMA | EVDO | GSM | WCDMA):
+ case (LTE | RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA):
type = RILConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA;
break;
default:
@@ -339,6 +342,7 @@
case "CDMA": return CDMA;
case "EVDO": return EVDO;
case "WCDMA": return WCDMA;
+ case "LTE_CA": return RAF_LTE_CA;
default: return RAF_UNKNOWN;
}
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 39a9295..8446dd0 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -155,6 +155,12 @@
*/
public static final int RIL_RADIO_TECHNOLOGY_IWLAN = 18;
+ /**
+ * LTE_CA
+ * @hide
+ */
+ public static final int RIL_RADIO_TECHNOLOGY_LTE_CA = 19;
+
/** @hide */
public static final int RIL_RADIO_CDMA_TECHNOLOGY_BITMASK =
(1 << (RIL_RADIO_TECHNOLOGY_IS95A - 1))
@@ -746,6 +752,9 @@
case RIL_RADIO_TECHNOLOGY_TD_SCDMA:
rtString = "TD-SCDMA";
break;
+ case RIL_RADIO_TECHNOLOGY_LTE_CA:
+ rtString = "LTE_CA";
+ break;
default:
rtString = "Unexpected";
Rlog.w(LOG_TAG, "Unexpected radioTechnology=" + rt);
@@ -1088,6 +1097,8 @@
return TelephonyManager.NETWORK_TYPE_TD_SCDMA;
case ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN:
return TelephonyManager.NETWORK_TYPE_IWLAN;
+ case ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA:
+ return TelephonyManager.NETWORK_TYPE_LTE_CA;
default:
return TelephonyManager.NETWORK_TYPE_UNKNOWN;
}
@@ -1139,7 +1150,9 @@
|| radioTechnology == RIL_RADIO_TECHNOLOGY_HSPAP
|| radioTechnology == RIL_RADIO_TECHNOLOGY_GSM
|| radioTechnology == RIL_RADIO_TECHNOLOGY_TD_SCDMA
- || radioTechnology == RIL_RADIO_TECHNOLOGY_IWLAN;
+ || radioTechnology == RIL_RADIO_TECHNOLOGY_IWLAN
+ || radioTechnology == RIL_RADIO_TECHNOLOGY_LTE_CA;
+
}
/** @hide */
@@ -1154,6 +1167,12 @@
}
/** @hide */
+ public static boolean isLte(int radioTechnology) {
+ return radioTechnology == RIL_RADIO_TECHNOLOGY_LTE ||
+ radioTechnology == RIL_RADIO_TECHNOLOGY_LTE_CA;
+ }
+
+ /** @hide */
public static boolean bearerBitmapHasCdma(int radioTechnologyBitmap) {
return (RIL_RADIO_CDMA_TECHNOLOGY_BITMASK & radioTechnologyBitmap) != 0;
}
diff --git a/telephony/java/android/telephony/TelephonyHistogram.java b/telephony/java/android/telephony/TelephonyHistogram.java
index 9d9ce72..e1c3d7b 100644
--- a/telephony/java/android/telephony/TelephonyHistogram.java
+++ b/telephony/java/android/telephony/TelephonyHistogram.java
@@ -31,35 +31,35 @@
public final class TelephonyHistogram implements Parcelable {
// Type of Telephony histogram Eg: RIL histogram will have all timing data associated with
// RIL calls. Similarly we can have any other Telephony histogram.
- private final int category;
+ private final int mCategory;
// Unique Id identifying a sample within particular category of histogram
- private final int id;
+ private final int mId;
// Min time taken in ms
- private int minTimeMs;
+ private int mMinTimeMs;
// Max time taken in ms
- private int maxTimeMs;
+ private int mMaxTimeMs;
// Average time taken in ms
- private int averageTimeMs;
+ private int mAverageTimeMs;
// Total count of samples
- private int sampleCount;
+ private int mSampleCount;
// Array storing time taken for first #RANGE_CALCULATION_COUNT samples of histogram.
- private int[] initialTimings;
+ private int[] mInitialTimings;
// Total number of time ranges expected (must be greater than 1)
- private final int bucketCount;
+ private final int mBucketCount;
// Array storing endpoints of range buckets. Calculated based on values of minTime & maxTime
// after totalTimeCount is #RANGE_CALCULATION_COUNT.
- private final int[] bucketEndPoints;
+ private final int[] mBucketEndPoints;
// Array storing counts for each time range starting from smallest value range
- private final int[] bucketCounters;
+ private final int[] mBucketCounters;
/**
* Constant for Telephony category
@@ -81,69 +81,85 @@
if (bucketCount <= 1) {
throw new IllegalArgumentException("Invalid number of buckets");
}
- this.category = category;
- this.id = id;
- this.minTimeMs = Integer.MAX_VALUE;
- this.maxTimeMs = 0;
- this.averageTimeMs = 0;
- this.sampleCount = 0;
- initialTimings = new int[RANGE_CALCULATION_COUNT];
- this.bucketCount = bucketCount;
- bucketEndPoints = new int[bucketCount - 1];
- bucketCounters = new int[bucketCount];
+ mCategory = category;
+ mId = id;
+ mMinTimeMs = Integer.MAX_VALUE;
+ mMaxTimeMs = 0;
+ mAverageTimeMs = 0;
+ mSampleCount = 0;
+ mInitialTimings = new int[RANGE_CALCULATION_COUNT];
+ mBucketCount = bucketCount;
+ mBucketEndPoints = new int[bucketCount - 1];
+ mBucketCounters = new int[bucketCount];
}
public TelephonyHistogram(TelephonyHistogram th) {
- category = th.getCategory();
- id = th.getId();
- minTimeMs = th.getMinTime();
- maxTimeMs = th.getMaxTime();
- averageTimeMs = th.getAverageTime();
- sampleCount = th.getSampleCount();
- initialTimings = th.getInitialTimings();
- bucketCount = th.getBucketCount();
- bucketEndPoints = th.getBucketEndPoints();
- bucketCounters = th.getBucketCounters();
+ mCategory = th.getCategory();
+ mId = th.getId();
+ mMinTimeMs = th.getMinTime();
+ mMaxTimeMs = th.getMaxTime();
+ mAverageTimeMs = th.getAverageTime();
+ mSampleCount = th.getSampleCount();
+ mInitialTimings = th.getInitialTimings();
+ mBucketCount = th.getBucketCount();
+ mBucketEndPoints = th.getBucketEndPoints();
+ mBucketCounters = th.getBucketCounters();
}
public int getCategory() {
- return category;
+ return mCategory;
}
public int getId() {
- return id;
+ return mId;
}
public int getMinTime() {
- return minTimeMs;
+ return mMinTimeMs;
}
public int getMaxTime() {
- return maxTimeMs;
+ return mMaxTimeMs;
}
public int getAverageTime() {
- return averageTimeMs;
+ return mAverageTimeMs;
}
public int getSampleCount () {
- return sampleCount;
+ return mSampleCount;
}
private int[] getInitialTimings() {
- return initialTimings;
+ return mInitialTimings;
}
public int getBucketCount() {
- return bucketCount;
+ return mBucketCount;
}
public int[] getBucketEndPoints() {
- return getDeepCopyOfArray(bucketEndPoints);
+ if (mSampleCount > 1 && mSampleCount < 10) {
+ int[] tempEndPoints = new int[mBucketCount - 1];
+ calculateBucketEndPoints(tempEndPoints);
+ return tempEndPoints;
+ } else {
+ return getDeepCopyOfArray(mBucketEndPoints);
+ }
}
public int[] getBucketCounters() {
- return getDeepCopyOfArray(bucketCounters);
+ if (mSampleCount > 1 && mSampleCount < 10) {
+ int[] tempEndPoints = new int[mBucketCount - 1];
+ int[] tempBucketCounters = new int[mBucketCount];
+ calculateBucketEndPoints(tempEndPoints);
+ for (int j = 0; j < mSampleCount; j++) {
+ addToBucketCounter(tempEndPoints, tempBucketCounters, mInitialTimings[j]);
+ }
+ return tempBucketCounters;
+ } else {
+ return getDeepCopyOfArray(mBucketCounters);
+ }
}
private int[] getDeepCopyOfArray(int[] array) {
@@ -152,7 +168,7 @@
return clone;
}
- private void addToBucketCounter(int time) {
+ private void addToBucketCounter(int[] bucketEndPoints, int[] bucketCounters, int time) {
int i;
for (i = 0; i < bucketEndPoints.length; i++) {
if (time <= bucketEndPoints[i]) {
@@ -163,6 +179,13 @@
bucketCounters[i]++;
}
+ private void calculateBucketEndPoints(int[] bucketEndPoints) {
+ for (int i = 1; i < mBucketCount; i++) {
+ int endPt = mMinTimeMs + (i * (mMaxTimeMs - mMinTimeMs)) / mBucketCount;
+ bucketEndPoints[i - 1] = endPt;
+ }
+ }
+
// Add new value of time taken
// This function updates minTime, maxTime, averageTime & totalTimeCount every time it is
// called. initialTimings[] is updated if totalTimeCount <= #RANGE_CALCULATION_COUNT. When
@@ -172,65 +195,62 @@
public void addTimeTaken(int time) {
// Initialize all fields if its first entry or if integer overflow is going to occur while
// trying to calculate averageTime
- if (sampleCount == 0 || (sampleCount == Integer.MAX_VALUE)) {
- if (sampleCount == 0) {
- minTimeMs = time;
- maxTimeMs = time;
- averageTimeMs = time;
+ if (mSampleCount == 0 || (mSampleCount == Integer.MAX_VALUE)) {
+ if (mSampleCount == 0) {
+ mMinTimeMs = time;
+ mMaxTimeMs = time;
+ mAverageTimeMs = time;
} else {
- initialTimings = new int[RANGE_CALCULATION_COUNT];
+ mInitialTimings = new int[RANGE_CALCULATION_COUNT];
}
- sampleCount = 1;
- Arrays.fill(initialTimings, 0);
- initialTimings[0] = time;
- Arrays.fill(bucketEndPoints, 0);
- Arrays.fill(bucketCounters, 0);
+ mSampleCount = 1;
+ Arrays.fill(mInitialTimings, 0);
+ mInitialTimings[0] = time;
+ Arrays.fill(mBucketEndPoints, 0);
+ Arrays.fill(mBucketCounters, 0);
} else {
- if (time < minTimeMs) {
- minTimeMs = time;
+ if (time < mMinTimeMs) {
+ mMinTimeMs = time;
}
- if (time > maxTimeMs) {
- maxTimeMs = time;
+ if (time > mMaxTimeMs) {
+ mMaxTimeMs = time;
}
- long totalTime = ((long)averageTimeMs) * sampleCount + time;
- averageTimeMs = (int)(totalTime/++sampleCount);
+ long totalTime = ((long)mAverageTimeMs) * mSampleCount + time;
+ mAverageTimeMs = (int)(totalTime/++mSampleCount);
- if (sampleCount < RANGE_CALCULATION_COUNT) {
- initialTimings[sampleCount - 1] = time;
- } else if (sampleCount == RANGE_CALCULATION_COUNT) {
- initialTimings[sampleCount - 1] = time;
+ if (mSampleCount < RANGE_CALCULATION_COUNT) {
+ mInitialTimings[mSampleCount - 1] = time;
+ } else if (mSampleCount == RANGE_CALCULATION_COUNT) {
+ mInitialTimings[mSampleCount - 1] = time;
// Calculate bucket endpoints based on bucketCount expected
- for (int i = 1; i < bucketCount; i++) {
- int endPt = minTimeMs + (i * (maxTimeMs - minTimeMs)) / bucketCount;
- bucketEndPoints[i - 1] = endPt;
- }
+ calculateBucketEndPoints(mBucketEndPoints);
// Use values stored in initialTimings[] to update bucketCounters
for (int j = 0; j < RANGE_CALCULATION_COUNT; j++) {
- addToBucketCounter(initialTimings[j]);
+ addToBucketCounter(mBucketEndPoints, mBucketCounters, mInitialTimings[j]);
}
- initialTimings = null;
+ mInitialTimings = null;
} else {
- addToBucketCounter(time);
+ addToBucketCounter(mBucketEndPoints, mBucketCounters, time);
}
}
}
public String toString() {
- String basic = " Histogram id = " + id + " Time(ms): min = " + minTimeMs + " max = "
- + maxTimeMs + " avg = " + averageTimeMs + " Count = " + sampleCount;
- if (sampleCount < RANGE_CALCULATION_COUNT) {
+ String basic = " Histogram id = " + mId + " Time(ms): min = " + mMinTimeMs + " max = "
+ + mMaxTimeMs + " avg = " + mAverageTimeMs + " Count = " + mSampleCount;
+ if (mSampleCount < RANGE_CALCULATION_COUNT) {
return basic;
} else {
StringBuffer intervals = new StringBuffer(" Interval Endpoints:");
- for (int i = 0; i < bucketEndPoints.length; i++) {
- intervals.append(" " + bucketEndPoints[i]);
+ for (int i = 0; i < mBucketEndPoints.length; i++) {
+ intervals.append(" " + mBucketEndPoints[i]);
}
intervals.append(" Interval counters:");
- for (int i = 0; i < bucketCounters.length; i++) {
- intervals.append(" " + bucketCounters[i]);
+ for (int i = 0; i < mBucketCounters.length; i++) {
+ intervals.append(" " + mBucketCounters[i]);
}
return basic + intervals;
}
@@ -251,39 +271,39 @@
};
public TelephonyHistogram(Parcel in) {
- category = in.readInt();
- id = in.readInt();
- minTimeMs = in.readInt();
- maxTimeMs = in.readInt();
- averageTimeMs = in.readInt();
- sampleCount = in.readInt();
+ mCategory = in.readInt();
+ mId = in.readInt();
+ mMinTimeMs = in.readInt();
+ mMaxTimeMs = in.readInt();
+ mAverageTimeMs = in.readInt();
+ mSampleCount = in.readInt();
if (in.readInt() == PRESENT) {
- initialTimings = new int[RANGE_CALCULATION_COUNT];
- in.readIntArray(initialTimings);
+ mInitialTimings = new int[RANGE_CALCULATION_COUNT];
+ in.readIntArray(mInitialTimings);
}
- bucketCount = in.readInt();
- bucketEndPoints = new int[bucketCount - 1];
- in.readIntArray(bucketEndPoints);
- bucketCounters = new int[bucketCount];
- in.readIntArray(bucketCounters);
+ mBucketCount = in.readInt();
+ mBucketEndPoints = new int[mBucketCount - 1];
+ in.readIntArray(mBucketEndPoints);
+ mBucketCounters = new int[mBucketCount];
+ in.readIntArray(mBucketCounters);
}
public void writeToParcel(Parcel out, int flags) {
- out.writeInt(category);
- out.writeInt(id);
- out.writeInt(minTimeMs);
- out.writeInt(maxTimeMs);
- out.writeInt(averageTimeMs);
- out.writeInt(sampleCount);
- if (initialTimings == null) {
+ out.writeInt(mCategory);
+ out.writeInt(mId);
+ out.writeInt(mMinTimeMs);
+ out.writeInt(mMaxTimeMs);
+ out.writeInt(mAverageTimeMs);
+ out.writeInt(mSampleCount);
+ if (mInitialTimings == null) {
out.writeInt(ABSENT);
} else {
out.writeInt(PRESENT);
- out.writeIntArray(initialTimings);
+ out.writeIntArray(mInitialTimings);
}
- out.writeInt(bucketCount);
- out.writeIntArray(bucketEndPoints);
- out.writeIntArray(bucketCounters);
+ out.writeInt(mBucketCount);
+ out.writeIntArray(mBucketEndPoints);
+ out.writeIntArray(mBucketCounters);
}
@Override
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index e72fe49..8e36f48 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1445,13 +1445,14 @@
public static final int NETWORK_TYPE_EHRPD = 14;
/** Current network is HSPA+ */
public static final int NETWORK_TYPE_HSPAP = 15;
- /** Current network is GSM {@hide} */
+ /** Current network is GSM */
public static final int NETWORK_TYPE_GSM = 16;
- /** Current network is TD_SCDMA {@hide} */
+ /** Current network is TD_SCDMA */
public static final int NETWORK_TYPE_TD_SCDMA = 17;
- /** Current network is IWLAN {@hide} */
+ /** Current network is IWLAN */
public static final int NETWORK_TYPE_IWLAN = 18;
-
+ /** Current network is LTE_CA {@hide} */
+ public static final int NETWORK_TYPE_LTE_CA = 19;
/**
* @return the NETWORK_TYPE_xxxx for current data connection.
*/
@@ -1654,6 +1655,7 @@
return NETWORK_CLASS_3_G;
case NETWORK_TYPE_LTE:
case NETWORK_TYPE_IWLAN:
+ case NETWORK_TYPE_LTE_CA:
return NETWORK_CLASS_4_G;
default:
return NETWORK_CLASS_UNKNOWN;
@@ -1717,6 +1719,8 @@
return "TD_SCDMA";
case NETWORK_TYPE_IWLAN:
return "IWLAN";
+ case NETWORK_TYPE_LTE_CA:
+ return "LTE_CA";
default:
return "UNKNOWN";
}
diff --git a/telephony/java/com/android/ims/ImsCallProfile.java b/telephony/java/com/android/ims/ImsCallProfile.java
index 92b70e8..65254d8 100644
--- a/telephony/java/com/android/ims/ImsCallProfile.java
+++ b/telephony/java/com/android/ims/ImsCallProfile.java
@@ -448,6 +448,15 @@
}
/**
+ * Determines if the {@link ImsCallProfile} represents a video call.
+ *
+ * @return {@code true} if the profile is for a video call, {@code false} otherwise.
+ */
+ public boolean isVideoCall() {
+ return VideoProfile.isVideo(getVideoStateFromCallType(mCallType));
+ }
+
+ /**
* Determines if a video state is set in a video state bit-mask.
*
* @param videoState The video state bit mask.
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index 70a8653..6115656 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -184,7 +184,7 @@
*/
void sendTextForSubscriberWithSelfPermissions(in int subId, String callingPkg,
in String destAddr, in String scAddr, in String text, in PendingIntent sentIntent,
- in PendingIntent deliveryIntent);
+ in PendingIntent deliveryIntent, in boolean persistMessage);
/**
* Inject an SMS PDU into the android platform.
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 1680fe3..b417a1c 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -208,4 +208,14 @@
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;
+
+ /**
+ * Value for the global property CELL_ON
+ * 0: Cell radio is off
+ * 1: Cell radio is on
+ * 2: Cell radio is off because airplane mode is enabled
+ */
+ public static final int CELL_OFF_FLAG = 0;
+ public static final int CELL_ON_FLAG = 1;
+ public static final int CELL_OFF_DUE_TO_AIRPLANE_MODE_FLAG = 2;
}
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index b14fc41..9471326 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -702,6 +702,12 @@
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public Display getDisplay() {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public File[] getExternalFilesDirs(String type) {
throw new UnsupportedOperationException();
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 0286506..a726a15 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -93,7 +93,7 @@
try {
mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false, false, null,
- Configuration.EMPTY, 0, false, false);
+ Configuration.EMPTY, 0, false, false, 0);
fail("IWindowManager.addAppToken did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
diff --git a/tools/aapt/ResourceFilter.cpp b/tools/aapt/ResourceFilter.cpp
index 8693999..ed06f60 100644
--- a/tools/aapt/ResourceFilter.cpp
+++ b/tools/aapt/ResourceFilter.cpp
@@ -54,6 +54,46 @@
return NO_ERROR;
}
+// Returns true if the locale script of the config should be considered matching
+// the locale script of entry.
+//
+// If both the scripts are empty, the scripts are considered matching for
+// backward compatibility reasons.
+//
+// If only one script is empty, we try to compute it based on the provided
+// language and country. If we could not compute it, we assume it's either a
+// new language we don't know about, or a private use language. We return true
+// since we don't know any better and they might as well be a match.
+//
+// Finally, when we have two scripts (one of which could be computed), we return
+// true if and only if they are an exact match.
+inline bool
+scriptsMatch(const ResTable_config& config, const ResTable_config& entry) {
+ const char* configScript = config.localeScript;
+ const char* entryScript = entry.localeScript;
+ if (configScript[0] == '\0' && entryScript[0] == '\0') {
+ return true; // both scripts are empty. We match for backward compatibility reasons.
+ }
+
+ char scriptBuffer[sizeof(config.localeScript)];
+ if (configScript[0] == '\0') {
+ localeDataComputeScript(scriptBuffer, config.language, config.country);
+ if (scriptBuffer[0] == '\0') { // We can't compute the script, so we match.
+ return true;
+ }
+ configScript = scriptBuffer;
+ } else if (entryScript[0] == '\0') {
+ localeDataComputeScript(
+ scriptBuffer, entry.language, entry.country);
+ if (scriptBuffer[0] == '\0') { // We can't compute the script, so we match.
+ return true;
+ }
+ entryScript = scriptBuffer;
+ }
+ return (memcmp(configScript, entryScript, sizeof(config.localeScript)) == 0);
+}
+
+
bool
WeakResourceFilter::match(const ResTable_config& config) const
{
@@ -75,11 +115,19 @@
// If the locales differ, but the languages are the same and
// the locale we are matching only has a language specified,
// we match.
- if (config.language[0] &&
- memcmp(config.language, entry.first.language, sizeof(config.language)) == 0) {
- if (config.country[0] == 0) {
- matchedAxis |= ResTable_config::CONFIG_LOCALE;
- }
+ //
+ // Exception: we won't match if a script is specified for at least
+ // one of the locales and it's different from the other locale's
+ // script. (We will compute the other script if at least one of the
+ // scripts were explicitly set. In cases we can't compute an script,
+ // we match.)
+ if (config.language[0] != '\0' &&
+ config.country[0] == '\0' &&
+ config.localeVariant[0] == '\0' &&
+ config.language[0] == entry.first.language[0] &&
+ config.language[1] == entry.first.language[1] &&
+ scriptsMatch(config, entry.first)) {
+ matchedAxis |= ResTable_config::CONFIG_LOCALE;
}
} else if ((diff & entry.second) == ResTable_config::CONFIG_SMALLEST_SCREEN_SIZE) {
// Special case if the smallest screen width doesn't match. We check that the
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index ceebdd5..04a59bcf 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -78,7 +78,7 @@
@Override
public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
boolean arg5, boolean arg6, int arg7, int arg8, boolean arg9, boolean arg10,
- Rect arg11, Configuration arg12, int arg13, boolean arg14, boolean arg15)
+ Rect arg11, Configuration arg12, int arg13, boolean arg14, boolean arg15, int arg16)
throws RemoteException {
// TODO Auto-generated method stub
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index f87269b..616cb57 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -1799,6 +1799,12 @@
}
@Override
+ public Display getDisplay() {
+ // pass
+ return null;
+ }
+
+ @Override
public int getUserId() {
return 0; // not used
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
index 3f276c9..ab73a8b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
@@ -16,11 +16,13 @@
package com.android.layoutlib.bridge.android;
+import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
import com.android.internal.view.IInputMethodManager;
import com.android.internal.view.InputBindResult;
+import android.net.Uri;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -239,4 +241,11 @@
// TODO Auto-generated method stub
return null;
}
+
+ @Override
+ public IInputContentUriToken createInputContentUriToken(IBinder token, Uri contentUri,
+ String packageName) {
+ // TODO Auto-generated method stub
+ return null;
+ }
}
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index a404a90..590ff1b 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -691,7 +691,7 @@
/**
* spread (i.e. max - min) distance
- * @deprecate Use {@link android.net.wifi.RttManager.RttResult#distanceSpread} API.
+ * @deprecated Use {@link android.net.wifi.RttManager.RttResult#distanceSpread} API.
*/
@Deprecated
public int distance_spread_cm;
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index b614a86..08ad35e 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -375,7 +375,15 @@
return false;
}
+ // wpa_supplicant can update the anonymous identity for these kinds of networks after
+ // framework reads them, so make sure the framework doesn't try to overwrite them.
+ boolean shouldNotWriteAnonIdentity = mEapMethod == WifiEnterpriseConfig.Eap.SIM
+ || mEapMethod == WifiEnterpriseConfig.Eap.AKA
+ || mEapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME;
for (String key : mFields.keySet()) {
+ if (shouldNotWriteAnonIdentity && ANON_IDENTITY_KEY.equals(key)) {
+ continue;
+ }
if (!saver.saveValue(key, mFields.get(key))) {
return false;
}
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 2ee1aef..2636c3f 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -141,7 +141,7 @@
/**
* reports {@link ScanListener#onResults} when underlying buffers are full
* this is simply the lack of the {@link #REPORT_EVENT_AFTER_EACH_SCAN} flag
- * @deprecated
+ * @deprecated It is not supported anymore.
*/
@Deprecated
public static final int REPORT_EVENT_AFTER_BUFFER_FULL = 0;
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
index ca737f9..32673c7 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
@@ -146,7 +146,6 @@
}
if (nameValue[0].equals("persistent")) {
- mOwner = new WifiP2pDevice(sa);
mNetId = Integer.parseInt(nameValue[1]);
continue;
}